summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--apct-tests/perftests/rubidium/Android.bp1
-rw-r--r--apct-tests/perftests/rubidium/assets/rubidium_bidding_logic_compiled.js72
-rw-r--r--apct-tests/perftests/rubidium/assets/rubidium_scoring_logic_compiled.js59
-rw-r--r--apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java255
-rw-r--r--apct-tests/perftests/settingsprovider/Android.bp39
-rw-r--r--apct-tests/perftests/settingsprovider/AndroidManifest.xml31
-rw-r--r--apct-tests/perftests/settingsprovider/OWNERS1
-rw-r--r--apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java120
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobService.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java14
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java144
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java29
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java47
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java13
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java20
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java23
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java6
-rw-r--r--core/api/current.txt142
-rw-r--r--core/api/system-current.txt26
-rw-r--r--core/api/test-current.txt19
-rw-r--r--core/java/android/app/ActivityManager.java32
-rw-r--r--core/java/android/app/AppOpsManager.java81
-rw-r--r--core/java/android/app/ContextImpl.java6
-rw-r--r--core/java/android/app/Dialog.java3
-rw-r--r--core/java/android/app/ForegroundServiceTypePolicy.java41
-rw-r--r--core/java/android/app/IActivityManager.aidl8
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl5
-rw-r--r--core/java/android/app/WallpaperManager.java75
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java24
-rw-r--r--core/java/android/app/time/TimeState.java8
-rw-r--r--core/java/android/app/time/TimeZoneState.java6
-rw-r--r--core/java/android/app/time/UnixEpochTime.java7
-rw-r--r--core/java/android/companion/AssociationRequest.java32
-rw-r--r--core/java/android/companion/virtual/VirtualDevice.java4
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceManager.java43
-rw-r--r--core/java/android/companion/virtual/camera/VirtualCameraDevice.java82
-rw-r--r--core/java/android/companion/virtual/camera/VirtualCameraInput.java54
-rw-r--r--core/java/android/companion/virtual/camera/VirtualCameraOutput.java197
-rw-r--r--core/java/android/content/Context.java4
-rw-r--r--core/java/android/content/Intent.java24
-rw-r--r--core/java/android/content/pm/ServiceInfo.java7
-rw-r--r--core/java/android/content/pm/UserProperties.java61
-rw-r--r--core/java/android/content/res/Resources.java15
-rw-r--r--core/java/android/credentials/CredentialManager.java207
-rw-r--r--core/java/android/credentials/ICredentialManager.aidl8
-rw-r--r--core/java/android/credentials/IListEnabledProvidersCallback.aidl29
-rw-r--r--core/java/android/credentials/ISetEnabledProvidersCallback.aidl (renamed from services/permission/java/com/android/server/permission/access/external/RoSystemProperties.kt)19
-rw-r--r--core/java/android/credentials/ListEnabledProvidersException.java74
-rw-r--r--core/java/android/credentials/ListEnabledProvidersResponse.aidl (renamed from services/permission/java/com/android/server/permission/access/external/UserHandle.kt)18
-rw-r--r--core/java/android/credentials/ListEnabledProvidersResponse.java85
-rw-r--r--core/java/android/credentials/SetEnabledProvidersException.java74
-rw-r--r--core/java/android/credentials/SetEnabledProvidersRequest.aidl19
-rw-r--r--core/java/android/credentials/SetEnabledProvidersRequest.java81
-rw-r--r--core/java/android/hardware/Camera.java24
-rw-r--r--core/java/android/hardware/SystemSensorManager.java6
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java43
-rw-r--r--core/java/android/hardware/display/AmbientBrightnessDayStats.java2
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl4
-rw-r--r--core/java/android/hardware/input/InputManager.java12
-rw-r--r--core/java/android/net/vcn/VcnConfig.java108
-rw-r--r--core/java/android/os/CoolingDevice.java21
-rw-r--r--core/java/android/os/Debug.java16
-rw-r--r--core/java/android/os/Environment.java60
-rw-r--r--core/java/android/os/TEST_MAPPING9
-rw-r--r--core/java/android/os/Temperature.java20
-rw-r--r--core/java/android/os/incremental/IncrementalManager.java19
-rw-r--r--core/java/android/os/storage/StorageManager.java103
-rw-r--r--core/java/android/service/credentials/Action.java2
-rw-r--r--core/java/android/service/credentials/BeginCreateCredentialResponse.java2
-rw-r--r--core/java/android/service/credentials/BeginGetCredentialOption.java129
-rw-r--r--core/java/android/service/credentials/BeginGetCredentialsRequest.aidl (renamed from core/java/android/service/credentials/GetCredentialsRequest.aidl)2
-rw-r--r--core/java/android/service/credentials/BeginGetCredentialsRequest.java175
-rw-r--r--core/java/android/service/credentials/BeginGetCredentialsResponse.aidl3
-rw-r--r--core/java/android/service/credentials/BeginGetCredentialsResponse.java (renamed from core/java/android/service/credentials/GetCredentialsResponse.java)36
-rw-r--r--core/java/android/service/credentials/CredentialEntry.java64
-rw-r--r--core/java/android/service/credentials/CredentialProviderService.java91
-rw-r--r--core/java/android/service/credentials/CredentialsResponseContent.java6
-rw-r--r--core/java/android/service/credentials/GetCredentialRequest.java (renamed from core/java/android/service/credentials/GetCredentialsRequest.java)28
-rw-r--r--core/java/android/service/credentials/GetCredentialsResponse.aidl3
-rw-r--r--core/java/android/service/credentials/IBeginGetCredentialsCallback.aidl (renamed from core/java/android/service/credentials/IGetCredentialsCallback.aidl)6
-rw-r--r--core/java/android/service/credentials/ICredentialProviderService.aidl6
-rw-r--r--core/java/android/service/voice/AbstractHotwordDetector.java20
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java54
-rw-r--r--core/java/android/service/voice/HotwordDetector.java14
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java2
-rwxr-xr-xcore/java/android/util/DisplayMetrics.java11
-rw-r--r--core/java/android/util/FeatureFlagUtils.java12
-rw-r--r--core/java/android/view/Display.java3
-rw-r--r--core/java/android/view/IWindow.aidl2
-rw-r--r--core/java/android/view/IWindowManager.aidl6
-rw-r--r--core/java/android/view/KeyEvent.java8
-rw-r--r--core/java/android/view/SurfaceControl.java10
-rw-r--r--core/java/android/view/ViewRootImpl.java103
-rw-r--r--core/java/android/view/WindowCallbacks.java18
-rw-r--r--core/java/android/view/WindowMetrics.java78
-rw-r--r--core/java/android/view/WindowlessWindowManager.java4
-rw-r--r--core/java/android/window/TaskConstants.java106
-rw-r--r--core/java/android/window/TaskFragmentOrganizer.java116
-rw-r--r--core/java/android/window/WindowOrganizer.java14
-rw-r--r--core/java/com/android/internal/inputmethod/InputBindResult.java5
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java16
-rw-r--r--core/java/com/android/internal/policy/DecorView.java13
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java2
-rw-r--r--core/jni/android_hardware_Camera.cpp144
-rw-r--r--core/jni/android_media_AudioMixerAttributes.h51
-rw-r--r--core/jni/android_media_AudioSystem.cpp270
-rw-r--r--core/jni/android_os_Debug.cpp7
-rw-r--r--core/jni/android_view_SurfaceControl.cpp7
-rw-r--r--core/proto/OWNERS1
-rw-r--r--core/res/AndroidManifest.xml23
-rw-r--r--core/res/res/values/config.xml14
-rw-r--r--core/res/res/values/strings.xml58
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/companion/virtual/OWNERS3
-rw-r--r--core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java128
-rw-r--r--core/tests/coretests/src/android/content/ContextTest.java8
-rw-r--r--core/tests/coretests/src/android/os/EnvironmentTest.java47
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java26
-rw-r--r--data/etc/com.android.settings.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--data/etc/services.core.protolog.json24
-rw-r--r--data/keyboards/Generic.kl2
-rw-r--r--identity/java/android/security/identity/AuthenticationKeyMetadata.java53
-rw-r--r--identity/java/android/security/identity/CredentialDataResult.java24
-rw-r--r--identity/java/android/security/identity/CredstoreCredentialDataResult.java5
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredential.java49
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredentialStore.java26
-rw-r--r--identity/java/android/security/identity/CredstorePresentationSession.java7
-rw-r--r--identity/java/android/security/identity/CredstoreResultData.java19
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java79
-rw-r--r--identity/java/android/security/identity/PresentationSession.java3
-rw-r--r--identity/java/android/security/identity/ResultData.java4
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java34
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TransactionManager.java28
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TransactionManagerTest.java22
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings_tv.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings.xml3
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings.xml3
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java109
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java154
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java18
-rw-r--r--libs/hwui/Properties.cpp4
-rw-r--r--libs/hwui/jni/Mesh.cpp40
-rw-r--r--location/java/android/location/LocationManager.java15
-rw-r--r--location/java/android/location/provider/LocationProviderBase.java2
-rw-r--r--media/java/android/media/AudioDeviceInfo.java2
-rw-r--r--media/java/android/media/AudioManager.java215
-rw-r--r--media/java/android/media/AudioMixerAttributes.aidl18
-rw-r--r--media/java/android/media/AudioMixerAttributes.java194
-rw-r--r--media/java/android/media/AudioSystem.java48
-rw-r--r--media/java/android/media/IAudioService.aidl12
-rw-r--r--media/java/android/media/IPreferredMixerAttributesDispatcher.aidl (renamed from services/permission/java/com/android/server/permission/access/external/PackageInfoUtils.kt)29
-rw-r--r--media/java/android/media/MediaMetrics.java40
-rw-r--r--media/java/android/media/RouteListingPreference.java16
-rw-r--r--media/java/android/media/midi/IMidiManager.aidl3
-rw-r--r--media/java/android/media/midi/MidiDeviceServer.java20
-rw-r--r--media/java/android/media/midi/MidiInputPort.java11
-rw-r--r--media/java/android/media/midi/MidiOutputPort.java11
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java9
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java5
-rw-r--r--packages/CarrierDefaultApp/res/values-af/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ar/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-as/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-az/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-be/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-bg/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-bn/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-bs/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ca/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-cs/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-da/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-de/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-el/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-es-rUS/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-es/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-et/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-eu/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-fa/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-fi/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-fr/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-gl/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-gu/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-hi/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-hr/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-hu/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-hy/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-in/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-is/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-it/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-iw/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ja/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ka/strings.xml16
-rw-r--r--packages/CarrierDefaultApp/res/values-kk/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-km/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-kn/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ko/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ky/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-lo/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-lt/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-lv/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-mk/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ml/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-mn/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-mr/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ms/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-my/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-nb/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ne/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-nl/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-or/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-pa/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-pl/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-pt/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ro/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ru/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-si/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-sl/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-sq/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-sr/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-sv/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-sw/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ta/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-te/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-th/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-tl/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-tr/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-uk/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-ur/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-uz/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-vi/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml18
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java17
-rw-r--r--packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java15
-rw-r--r--packages/CompanionDeviceManager/res/drawable-night/ic_permission_microphone.xml26
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_glasses.xml38
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_permission_microphone.xml24
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml28
-rw-r--r--packages/CompanionDeviceManager/res/values/strings.xml40
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java29
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java9
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java10
-rw-r--r--packages/CredentialManager/res/drawable/ic_face.xml30
-rw-r--r--packages/CredentialManager/res/drawable/ic_manage_accounts.xml30
-rw-r--r--packages/CredentialManager/res/values-af/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-am/strings.xml120
-rw-r--r--packages/CredentialManager/res/values-ar/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-as/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-az/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-b+sr+Latn/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-be/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-bg/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-bn/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-bs/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-ca/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-cs/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-da/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-de/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-el/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-en-rAU/strings.xml10
-rw-r--r--packages/CredentialManager/res/values-en-rCA/strings.xml6
-rw-r--r--packages/CredentialManager/res/values-en-rGB/strings.xml10
-rw-r--r--packages/CredentialManager/res/values-en-rIN/strings.xml10
-rw-r--r--packages/CredentialManager/res/values-en-rXC/strings.xml6
-rw-r--r--packages/CredentialManager/res/values-es-rUS/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-es/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-et/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-eu/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-fa/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-fi/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-fr-rCA/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-fr/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-gl/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-gu/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-hi/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-hr/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-hu/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-hy/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-in/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-is/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-it/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-iw/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-ja/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-ka/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-kk/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-km/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-kn/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-ko/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-ky/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-lo/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-lt/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-lv/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-mk/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-ml/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-mn/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-mr/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-ms/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-my/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-nb/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-ne/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-nl/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-or/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-pa/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-pl/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-pt-rBR/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-pt-rPT/strings.xml10
-rw-r--r--packages/CredentialManager/res/values-pt/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-ro/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-ru/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-si/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-sk/strings.xml10
-rw-r--r--packages/CredentialManager/res/values-sl/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-sq/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-sr/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-sv/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-sw/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-ta/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-te/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-th/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-tl/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-tr/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-uk/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-ur/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-uz/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-vi/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-zh-rCN/strings.xml37
-rw-r--r--packages/CredentialManager/res/values-zh-rHK/strings.xml33
-rw-r--r--packages/CredentialManager/res/values-zh-rTW/strings.xml31
-rw-r--r--packages/CredentialManager/res/values-zu/strings.xml16
-rw-r--r--packages/CredentialManager/res/values/strings.xml2
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt13
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt19
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt94
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt186
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt49
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt2
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt9
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt65
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt61
-rw-r--r--packages/PrintSpooler/res/values-ca/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-iw/strings.xml6
-rw-r--r--packages/SettingsLib/AppPreference/Android.bp1
-rw-r--r--packages/SettingsLib/Spa/gallery/AndroidManifest.xml7
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt4
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/dark_landscape_preference.pngbin41801 -> 0 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/dark_portrait_preference.pngbin76377 -> 0 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.pngbin0 -> 23689 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.pngbin0 -> 28829 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.pngbin0 -> 17824 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.pngbin0 -> 24040 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.pngbin0 -> 56253 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.pngbin0 -> 57182 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.pngbin0 -> 74572 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.pngbin41639 -> 53473 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.pngbin0 -> 81694 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.pngbin0 -> 60024 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.pngbin0 -> 9074 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.pngbin0 -> 94029 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.pngbin0 -> 77802 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.pngbin0 -> 19985 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.pngbin0 -> 23390 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.pngbin0 -> 17824 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.pngbin0 -> 15581 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.pngbin0 -> 41803 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.pngbin0 -> 50511 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.pngbin0 -> 64695 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.pngbin76120 -> 53509 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.pngbin0 -> 95616 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.pngbin0 -> 51275 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.pngbin0 -> 9074 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.pngbin0 -> 84176 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.pngbin0 -> 70504 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_landscape_preference.pngbin47896 -> 0 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.pngbin0 -> 11984 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.pngbin0 -> 14653 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.pngbin0 -> 10147 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.pngbin0 -> 11194 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.pngbin0 -> 28374 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.pngbin0 -> 29944 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.pngbin0 -> 38356 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.pngbin50068 -> 29792 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.pngbin0 -> 63231 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.pngbin0 -> 30698 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.pngbin0 -> 5360 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.pngbin0 -> 50602 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.pngbin0 -> 42864 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/light_landscape_preference.pngbin47669 -> 0 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/light_portrait_preference.pngbin49889 -> 0 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/res/drawable/accessibility_captioning_banner.xml52
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/button/ActionButtonsScreenshotTest.kt58
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt76
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/LineChartScreenshotTest.kt76
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/PieChartScreenshotTest.kt59
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/illustration/ImageIllustrationScreenshotTest.kt53
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/MainSwitchPreferenceScreenshotTest.kt65
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/PreferenceScreenshotTest.kt (renamed from packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/PreferenceScreenshotTest.kt)10
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/ProgressBarPreferenceScreenshotTest.kt88
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt73
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SwitchPreferenceScreenshotTest.kt102
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/TwoTargetSwitchPreferenceScreenshotTest.kt71
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/FooterScreenshotTest.kt48
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/SpinnerScreenshotTest.kt52
-rw-r--r--packages/SettingsLib/Spa/spa/Android.bp6
-rw-r--r--packages/SettingsLib/Spa/spa/build.gradle11
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugLogger.kt34
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt6
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt4
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt12
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt13
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt38
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt74
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/provider/Demo.kt2
-rw-r--r--packages/SettingsLib/Spa/tests/Android.bp5
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt34
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentTest.kt60
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt79
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/CollectionsTest.kt47
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt115
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt4
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/ProgressBarTest.kt49
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/TextTest.kt44
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java7
-rw-r--r--packages/Shell/AndroidManifest.xml77
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java3
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/TEST_MAPPING12
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt20
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt12
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt15
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/SystemUITypography.kt46
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypeScaleTokens.kt97
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypefaceTokens.kt74
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypographyTokens.kt142
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt11
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values/strings.xml32
-rw-r--r--packages/SystemUI/res-product/values/strings.xml8
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay.xml1
-rw-r--r--packages/SystemUI/res/layout/media_output_list_group_divider.xml35
-rw-r--r--packages/SystemUI/res/layout/screenshot_static.xml1
-rw-r--r--packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl11
-rw-r--r--packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java32
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ClockEventController.kt9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java19
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java25
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java222
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java141
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/TEST_MAPPING16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLog.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandler.java (renamed from packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationComponent.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationModule.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt76
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/BouncerLog.kt (renamed from services/permission/java/com/android/server/permission/access/external/CompatibilityPermissionInfo.kt)18
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java120
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiDebug.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java94
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java140
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt199
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/utils/MultiUserActionsEvent.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java455
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java (renamed from packages/SystemUI/src/com/android/systemui/wallpapers/canvas/WallpaperLocalColorExtractor.java)3
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java380
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java183
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java195
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java78
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt159
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt136
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java127
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java105
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java221
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandlerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java)3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java117
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt93
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt46
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java136
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt338
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt48
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleViewTest.kt58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java187
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractorTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/WallpaperLocalColorExtractorTest.java)2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java128
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java89
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java5
-rw-r--r--packages/SystemUI/unfold/Android.bp1
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt22
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt1
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt4
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt6
-rw-r--r--services/companion/java/com/android/server/companion/MetricUtils.java12
-rw-r--r--services/companion/java/com/android/server/companion/PermissionsUtils.java5
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java43
-rw-r--r--services/core/java/com/android/server/BinaryTransparencyService.java37
-rw-r--r--services/core/java/com/android/server/BootReceiver.java6
-rw-r--r--services/core/java/com/android/server/SystemConfig.java188
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java36
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java18
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java38
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java38
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java3
-rw-r--r--services/core/java/com/android/server/am/BroadcastConstants.java12
-rw-r--r--services/core/java/com/android/server/am/BroadcastProcessQueue.java29
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java10
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueImpl.java19
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java287
-rw-r--r--services/core/java/com/android/server/am/BroadcastReceiverBatch.java346
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java6
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java15
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java5
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java14
-rw-r--r--services/core/java/com/android/server/am/TEST_MAPPING9
-rw-r--r--services/core/java/com/android/server/am/UserController.java79
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java9
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java18
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java184
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java38
-rw-r--r--services/core/java/com/android/server/audio/SoundDoseHelper.java47
-rw-r--r--services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java17
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java248
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java4
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java4
-rw-r--r--services/core/java/com/android/server/incident/IncidentCompanionService.java36
-rw-r--r--services/core/java/com/android/server/incident/PendingReports.java51
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java8
-rw-r--r--services/core/java/com/android/server/input/KeyboardLayoutManager.java16
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java28
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java53
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java47
-rw-r--r--services/core/java/com/android/server/os/BugreportManagerServiceImpl.java21
-rw-r--r--services/core/java/com/android/server/pm/CloneProfileResolver.java26
-rw-r--r--services/core/java/com/android/server/pm/Computer.java3
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java10
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java100
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java4
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java26
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerLocal.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java36
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceInjector.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java86
-rw-r--r--services/core/java/com/android/server/pm/Settings.java4
-rw-r--r--services/core/java/com/android/server/pm/UserManagerInternal.java22
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java10
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java3
-rw-r--r--services/core/java/com/android/server/pm/UserVisibilityMediator.java2
-rw-r--r--services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java17
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionAllowlist.java140
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java83
-rw-r--r--services/core/java/com/android/server/policy/LegacyGlobalActions.java6
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java16
-rw-r--r--services/core/java/com/android/server/power/Notifier.java33
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java198
-rw-r--r--services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java2
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java15
-rw-r--r--services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java26
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java99
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java26
-rw-r--r--services/core/java/com/android/server/wm/DockedTaskDividerController.java63
-rw-r--r--services/core/java/com/android/server/wm/DragResizeMode.java47
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java3
-rw-r--r--services/core/java/com/android/server/wm/Task.java59
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java32
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java44
-rw-r--r--services/core/jni/stats/SurfaceFlingerPuller.cpp10
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd39
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt23
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java194
-rw-r--r--services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java15
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderGetSession.java89
-rw-r--r--services/credentials/java/com/android/server/credentials/RemoteCredentialService.java27
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java11
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java53
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java44
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/midi/java/com/android/server/midi/MidiService.java91
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessCheckingService.kt89
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessPolicy.kt118
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessState.kt23
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessUri.kt5
-rw-r--r--services/permission/java/com/android/server/permission/access/appop/AppOpService.kt (renamed from services/permission/java/com/android/server/permission/access/appop/AppOpsCheckingServiceCompatImpl.kt)10
-rw-r--r--services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt5
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/IndexedList.kt10
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/IndexedListSet.kt10
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt10
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/IndexedSet.kt10
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/IntMap.kt10
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/IntSet.kt20
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/List.kt10
-rw-r--r--services/permission/java/com/android/server/permission/access/data/Package.kt43
-rw-r--r--services/permission/java/com/android/server/permission/access/external/KnownPackages.kt34
-rw-r--r--services/permission/java/com/android/server/permission/access/external/PackageState.kt65
-rw-r--r--services/permission/java/com/android/server/permission/access/external/SigningDetails.kt42
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/Permission.kt (renamed from services/permission/java/com/android/server/permission/access/data/Permission.kt)2
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt1
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionService.kt (renamed from services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt)74
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt1
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt331
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java342
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java12
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java440
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java19
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java25
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java68
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java201
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java24
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/power/ThermalManagerServiceMockingTest.java218
-rw-r--r--services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java51
-rw-r--r--services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java81
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java82
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java104
-rw-r--r--services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java115
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java54
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestIWindow.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java9
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java24
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java91
-rw-r--r--telephony/java/android/telephony/SmsManager.java37
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java89
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java98
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java2
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java4
-rw-r--r--telephony/java/android/telephony/ims/RegistrationManager.java55
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl1
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl1
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl1
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl4
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java66
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java136
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java14
-rw-r--r--telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/ISms.aidl19
-rw-r--r--telephony/java/com/android/internal/telephony/ISmsImplBase.java10
-rw-r--r--telephony/java/com/android/internal/telephony/ISub.aidl5
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl31
-rw-r--r--tests/vcn/java/android/net/vcn/VcnConfigTest.java59
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java79
-rw-r--r--tools/aapt2/ApkInfo.proto6
-rw-r--r--tools/aapt2/cmd/Dump_test.cpp17
-rw-r--r--tools/aapt2/dump/DumpManifest.cpp281
-rw-r--r--tools/aapt2/integration-tests/DumpTest/built_with_aapt.apkbin0 -> 930 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt11
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_expected.txt1
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt15
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_full_proto.txt15
-rw-r--r--tools/lint/framework/Android.bp2
-rw-r--r--tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt7
864 files changed, 19984 insertions, 8744 deletions
diff --git a/Android.bp b/Android.bp
index 8820ee1fa719..2740ccc9a803 100644
--- a/Android.bp
+++ b/Android.bp
@@ -102,6 +102,7 @@ filegroup {
":android.hardware.keymaster-V4-java-source",
":android.hardware.security.keymint-V3-java-source",
":android.hardware.security.secureclock-V1-java-source",
+ ":android.hardware.thermal-V1-java-source",
":android.hardware.tv.tuner-V2-java-source",
":android.security.apc-java-source",
":android.security.authorization-java-source",
diff --git a/apct-tests/perftests/rubidium/Android.bp b/apct-tests/perftests/rubidium/Android.bp
index ba2b44241c5a..ebd228f76a1d 100644
--- a/apct-tests/perftests/rubidium/Android.bp
+++ b/apct-tests/perftests/rubidium/Android.bp
@@ -32,6 +32,7 @@ android_test {
"collector-device-lib-platform",
"compatibility-device-util-axt",
"platform-test-annotations",
+ "framework-adservices-lib",
"adservices-service-core",
"androidx.core_core",
],
diff --git a/apct-tests/perftests/rubidium/assets/rubidium_bidding_logic_compiled.js b/apct-tests/perftests/rubidium/assets/rubidium_bidding_logic_compiled.js
new file mode 100644
index 000000000000..3f853f1fd4d8
--- /dev/null
+++ b/apct-tests/perftests/rubidium/assets/rubidium_bidding_logic_compiled.js
@@ -0,0 +1,72 @@
+/*
+
+ Copyright The Closure Library Authors.
+ SPDX-License-Identifier: Apache-2.0
+*/
+'use strict';function ba(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}}var ca="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};
+function da(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var fa=da(this);function m(a,b){if(b)a:{var c=fa;a=a.split(".");for(var d=0;d<a.length-1;d++){var f=a[d];if(!(f in c))break a;c=c[f]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&ca(c,a,{configurable:!0,writable:!0,value:b})}}
+m("Symbol",function(a){function b(e){if(this instanceof b)throw new TypeError("Symbol is not a constructor");return new c(d+(e||"")+"_"+f++,e)}function c(e,h){this.h=e;ca(this,"description",{configurable:!0,writable:!0,value:h})}if(a)return a;c.prototype.toString=function(){return this.h};var d="jscomp_symbol_"+(1E9*Math.random()>>>0)+"_",f=0;return b});
+m("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c<b.length;c++){var d=fa[b[c]];"function"===typeof d&&"function"!=typeof d.prototype[a]&&ca(d.prototype,a,{configurable:!0,writable:!0,value:function(){return ia(ba(this))}})}return a});function ia(a){a={next:a};a[Symbol.iterator]=function(){return this};return a}
+function p(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):{next:ba(a)}}function ja(a){if(!(a instanceof Array)){a=p(a);for(var b,c=[];!(b=a.next()).done;)c.push(b.value);a=c}return a}var la="function"==typeof Object.create?Object.create:function(a){function b(){}b.prototype=a;return new b},ma;
+if("function"==typeof Object.setPrototypeOf)ma=Object.setPrototypeOf;else{var na;a:{var oa={a:!0},qa={};try{qa.__proto__=oa;na=qa.a;break a}catch(a){}na=!1}ma=na?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}var ra=ma;
+function q(a,b){a.prototype=la(b.prototype);a.prototype.constructor=a;if(ra)ra(a,b);else for(var c in b)if("prototype"!=c)if(Object.defineProperties){var d=Object.getOwnPropertyDescriptor(b,c);d&&Object.defineProperty(a,c,d)}else a[c]=b[c];a.Ia=b.prototype}function sa(){for(var a=Number(this),b=[],c=a;c<arguments.length;c++)b[c-a]=arguments[c];return b}function ta(a,b){return Object.prototype.hasOwnProperty.call(a,b)}
+m("WeakMap",function(a){function b(k){this.h=(g+=Math.random()+1).toString();if(k){k=p(k);for(var l;!(l=k.next()).done;)l=l.value,this.set(l[0],l[1])}}function c(){}function d(k){var l=typeof k;return"object"===l&&null!==k||"function"===l}function f(k){if(!ta(k,h)){var l=new c;ca(k,h,{value:l})}}function e(k){var l=Object[k];l&&(Object[k]=function(n){if(n instanceof c)return n;Object.isExtensible(n)&&f(n);return l(n)})}if(function(){if(!a||!Object.seal)return!1;try{var k=Object.seal({}),l=Object.seal({}),
+n=new a([[k,2],[l,3]]);if(2!=n.get(k)||3!=n.get(l))return!1;n.delete(k);n.set(l,4);return!n.has(k)&&4==n.get(l)}catch(t){return!1}}())return a;var h="$jscomp_hidden_"+Math.random();e("freeze");e("preventExtensions");e("seal");var g=0;b.prototype.set=function(k,l){if(!d(k))throw Error("Invalid WeakMap key");f(k);if(!ta(k,h))throw Error("WeakMap key fail: "+k);k[h][this.h]=l;return this};b.prototype.get=function(k){return d(k)&&ta(k,h)?k[h][this.h]:void 0};b.prototype.has=function(k){return d(k)&&ta(k,
+h)&&ta(k[h],this.h)};b.prototype.delete=function(k){return d(k)&&ta(k,h)&&ta(k[h],this.h)?delete k[h][this.h]:!1};return b});
+m("Map",function(a){function b(){var g={};return g.C=g.next=g.head=g}function c(g,k){var l=g.h;return ia(function(){if(l){for(;l.head!=g.h;)l=l.C;for(;l.next!=l.head;)return l=l.next,{done:!1,value:k(l)};l=null}return{done:!0,value:void 0}})}function d(g,k){var l=k&&typeof k;"object"==l||"function"==l?e.has(k)?l=e.get(k):(l=""+ ++h,e.set(k,l)):l="p_"+k;var n=g.u[l];if(n&&ta(g.u,l))for(g=0;g<n.length;g++){var t=n[g];if(k!==k&&t.key!==t.key||k===t.key)return{id:l,list:n,index:g,m:t}}return{id:l,list:n,
+index:-1,m:void 0}}function f(g){this.u={};this.h=b();this.size=0;if(g){g=p(g);for(var k;!(k=g.next()).done;)k=k.value,this.set(k[0],k[1])}}if(function(){if(!a||"function"!=typeof a||!a.prototype.entries||"function"!=typeof Object.seal)return!1;try{var g=Object.seal({x:4}),k=new a(p([[g,"s"]]));if("s"!=k.get(g)||1!=k.size||k.get({x:4})||k.set({x:4},"t")!=k||2!=k.size)return!1;var l=k.entries(),n=l.next();if(n.done||n.value[0]!=g||"s"!=n.value[1])return!1;n=l.next();return n.done||4!=n.value[0].x||
+"t"!=n.value[1]||!l.next().done?!1:!0}catch(t){return!1}}())return a;var e=new WeakMap;f.prototype.set=function(g,k){g=0===g?0:g;var l=d(this,g);l.list||(l.list=this.u[l.id]=[]);l.m?l.m.value=k:(l.m={next:this.h,C:this.h.C,head:this.h,key:g,value:k},l.list.push(l.m),this.h.C.next=l.m,this.h.C=l.m,this.size++);return this};f.prototype.delete=function(g){g=d(this,g);return g.m&&g.list?(g.list.splice(g.index,1),g.list.length||delete this.u[g.id],g.m.C.next=g.m.next,g.m.next.C=g.m.C,g.m.head=null,this.size--,
+!0):!1};f.prototype.clear=function(){this.u={};this.h=this.h.C=b();this.size=0};f.prototype.has=function(g){return!!d(this,g).m};f.prototype.get=function(g){return(g=d(this,g).m)&&g.value};f.prototype.entries=function(){return c(this,function(g){return[g.key,g.value]})};f.prototype.keys=function(){return c(this,function(g){return g.key})};f.prototype.values=function(){return c(this,function(g){return g.value})};f.prototype.forEach=function(g,k){for(var l=this.entries(),n;!(n=l.next()).done;)n=n.value,
+g.call(k,n[1],n[0],this)};f.prototype[Symbol.iterator]=f.prototype.entries;var h=0;return f});m("Number.isNaN",function(a){return a?a:function(b){return"number"===typeof b&&isNaN(b)}});function ua(a,b){a instanceof String&&(a+="");var c=0,d=!1,f={next:function(){if(!d&&c<a.length){var e=c++;return{value:b(e,a[e]),done:!1}}d=!0;return{done:!0,value:void 0}}};f[Symbol.iterator]=function(){return f};return f}m("Array.prototype.values",function(a){return a?a:function(){return ua(this,function(b,c){return c})}});
+m("Set",function(a){function b(c){this.h=new Map;if(c){c=p(c);for(var d;!(d=c.next()).done;)this.add(d.value)}this.size=this.h.size}if(function(){if(!a||"function"!=typeof a||!a.prototype.entries||"function"!=typeof Object.seal)return!1;try{var c=Object.seal({x:4}),d=new a(p([c]));if(!d.has(c)||1!=d.size||d.add(c)!=d||1!=d.size||d.add({x:4})!=d||2!=d.size)return!1;var f=d.entries(),e=f.next();if(e.done||e.value[0]!=c||e.value[1]!=c)return!1;e=f.next();return e.done||e.value[0]==c||4!=e.value[0].x||
+e.value[1]!=e.value[0]?!1:f.next().done}catch(h){return!1}}())return a;b.prototype.add=function(c){c=0===c?0:c;this.h.set(c,c);this.size=this.h.size;return this};b.prototype.delete=function(c){c=this.h.delete(c);this.size=this.h.size;return c};b.prototype.clear=function(){this.h.clear();this.size=0};b.prototype.has=function(c){return this.h.has(c)};b.prototype.entries=function(){return this.h.entries()};b.prototype.values=function(){return this.h.values()};b.prototype.keys=b.prototype.values;b.prototype[Symbol.iterator]=
+b.prototype.values;b.prototype.forEach=function(c,d){var f=this;this.h.forEach(function(e){return c.call(d,e,e,f)})};return b});m("globalThis",function(a){return a||fa});m("Object.is",function(a){return a?a:function(b,c){return b===c?0!==b||1/b===1/c:b!==b&&c!==c}});m("Array.prototype.includes",function(a){return a?a:function(b,c){var d=this;d instanceof String&&(d=String(d));var f=d.length;c=c||0;for(0>c&&(c=Math.max(c+f,0));c<f;c++){var e=d[c];if(e===b||Object.is(e,b))return!0}return!1}});
+m("String.prototype.includes",function(a){return a?a:function(b,c){if(null==this)throw new TypeError("The 'this' value for String.prototype.includes must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype.includes must not be a regular expression");return-1!==this.indexOf(b,c||0)}});m("Object.values",function(a){return a?a:function(b){var c=[],d;for(d in b)ta(b,d)&&c.push(b[d]);return c}});
+function va(a){var b=typeof a;return"object"==b&&null!=a||"function"==b};var wa={};var xa=Array.prototype.map?function(a,b){return Array.prototype.map.call(a,b,void 0)}:function(a,b){for(var c=a.length,d=Array(c),f="string"===typeof a?a.split(""):a,e=0;e<c;e++)e in f&&(d[e]=b.call(void 0,f[e],e,a));return d};var ya={},za=null;function Aa(a,b){void 0===b&&(b=0);Ba();b=ya[b];for(var c=Array(Math.floor(a.length/3)),d=b[64]||"",f=0,e=0;f<a.length-2;f+=3){var h=a[f],g=a[f+1],k=a[f+2],l=b[h>>2];h=b[(h&3)<<4|g>>4];g=b[(g&15)<<2|k>>6];k=b[k&63];c[e++]=l+h+g+k}l=0;k=d;switch(a.length-f){case 2:l=a[f+1],k=b[(l&15)<<2]||d;case 1:a=a[f],c[e]=b[a>>2]+b[(a&3)<<4|l>>4]+k+d}return c.join("")}
+function Ca(a){var b=a.length,c=3*b/4;c%3?c=Math.floor(c):-1!="=.".indexOf(a[b-1])&&(c=-1!="=.".indexOf(a[b-2])?c-2:c-1);var d=new Uint8Array(c),f=0;Da(a,function(e){d[f++]=e});return f!==c?d.subarray(0,f):d}
+function Da(a,b){function c(k){for(;d<a.length;){var l=a.charAt(d++),n=za[l];if(null!=n)return n;if(!/^[\s\xa0]*$/.test(l))throw Error("Unknown base64 encoding at char: "+l);}return k}Ba();for(var d=0;;){var f=c(-1),e=c(0),h=c(64),g=c(64);if(64===g&&-1===f)break;b(f<<2|e>>4);64!=h&&(b(e<<4&240|h>>2),64!=g&&b(h<<6&192|g))}}
+function Ba(){if(!za){za={};for(var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""),b=["+/=","+/","-_=","-_.","-_"],c=0;5>c;c++){var d=a.concat(b[c].split(""));ya[c]=d;for(var f=0;f<d.length;f++){var e=d[f];void 0===za[e]&&(za[e]=f)}}}};var Ea="undefined"!==typeof Uint8Array;function Fa(a){return null==a||Ga(a)?a:"string"===typeof a?Ca(a):null}function Ga(a){return Ea&&null!=a&&a instanceof Uint8Array}var Ha={};var Ia;function Qa(a){if(a!==Ha)throw Error("illegal external caller");}function Ra(a,b){Qa(b);this.aa=a;if(null!=a&&0===a.length)throw Error("ByteString should be constructed with non-empty values");}function Sa(){return Ia||(Ia=new Ra(null,Ha))}function Ta(a){var b=a.aa;return null==b?"":"string"===typeof b?b:a.aa=Aa(b)};var r="function"===typeof Symbol&&"symbol"===typeof Symbol()?Symbol():void 0;function u(a,b){if(r)return a[r]|=b;if(void 0!==a.A)return a.A|=b;Object.defineProperties(a,{A:{value:b,configurable:!0,writable:!0,enumerable:!1}});return b}function Ua(a,b){r?a[r]&&(a[r]&=~b):void 0!==a.A&&(a.A&=~b)}function v(a){var b;r?b=a[r]:b=a.A;return null==b?0:b}function Va(a,b){r?a[r]=b:void 0!==a.A?a.A=b:Object.defineProperties(a,{A:{value:b,configurable:!0,writable:!0,enumerable:!1}})}
+function $a(a){u(a,1);return a}function w(a){return!!(v(a)&2)}function ab(a){u(a,16);return a}function bb(a,b){Va(b,(a|0)&-51)}function cb(a,b){Va(b,(a|18)&-41)};var db={};function eb(a){return null!==a&&"object"===typeof a&&!Array.isArray(a)&&a.constructor===Object}function fb(a){a instanceof Ra&&(Qa(Ha),a=a.aa||"");return a}var gb,hb=[];Va(hb,23);gb=Object.freeze(hb);function ib(a){if(w(a.i))throw Error("Cannot mutate an immutable Message");}function jb(a){var b=a.length;(b=b?a[b-1]:void 0)&&eb(b)?b.g=1:(b={},a.push((b.g=1,b)))};function kb(a){return a}function lb(a){return a};function mb(a,b){a=a||{};b=b||{};var c={},d;for(d in a)c[d]=0;for(var f in b)c[f]=0;for(var e in c)if(!nb(a[e],b[e]))return!1;return!0}function ob(a){return a&&"object"===typeof a?a.i||a:a}
+function nb(a,b){a=fb(a);b=fb(b);a=ob(a);b=ob(b);if(a==b)return!0;if(Ea){var c=Ga(a),d=Ga(b);if(c||d){if(!c)if("string"===typeof a)a=Fa(a);else return!1;if(d)d=b;else if("string"===typeof b)d=Fa(b);else return!1;if(a.length!==d.length)return!1;for(b=0;b<a.length;b++)if(a[b]!==d[b])return!1;return!0}}if(null==a&&Array.isArray(b)&&v(b)&1&&!b.length||null==b&&Array.isArray(a)&&v(a)&1&&!a.length)return!0;if(!va(a)||!va(b))return"number"===typeof a&&isNaN(a)||"number"===typeof b&&isNaN(b)?String(a)==String(b):
+!1;if(a.constructor!=b.constructor)return!1;if(a.constructor===Array){d=a;c=a=void 0;for(var f=Math.max(d.length,b.length),e=0;e<f;e++){var h=d[e],g=b[e];h&&h.constructor==Object&&(a=h,h=void 0);g&&g.constructor==Object&&(c=g,g=void 0);if(!nb(h,g))return!1}return a||c?(a=a||{},c=c||{},mb(a,c)):!0}if(a.constructor===Object)return mb(a,b);throw Error("Invalid type in JSPB array");};var pb;function qb(a){switch(typeof a){case "number":return isFinite(a)?a:String(a);case "object":if(a)if(Array.isArray(a)){if(0!==(v(a)&128))return a=Array.prototype.slice.call(a),jb(a),a}else{if(Ga(a))return Aa(a);if(a instanceof Ra)return Ta(a)}}return a};function rb(a,b,c,d){if(null!=a){if(Array.isArray(a))a=sb(a,b,c,void 0!==d);else if(eb(a)){var f={},e;for(e in a)f[e]=rb(a[e],b,c,d);a=f}else a=b(a,d);return a}}function sb(a,b,c,d){var f=v(a);d=d?!!(f&16):void 0;a=Array.prototype.slice.call(a);for(var e=0;e<a.length;e++)a[e]=rb(a[e],b,c,d);c(f,a);return a}function tb(a){return a.Y===db?a.toJSON():qb(a)}function ub(a,b){a&128&&jb(b)};function vb(a){return a.h||(a.h=a.i[a.u+a.H]={})}function x(a,b,c){return-1===b?null:b>=a.u?a.h?a.h[b]:void 0:c&&a.h&&(c=a.h[b],null!=c)?c:a.i[b+a.H]}function wb(a,b,c,d){ib(a);return y(a,b,c,d)}function y(a,b,c,d){a.V&&(a.V=void 0);if(b>=a.u||d)return vb(a)[b]=c,a;a.i[b+a.H]=c;(c=a.h)&&b in c&&delete c[b];return a}
+function xb(a,b,c,d,f){var e=x(a,b,d);Array.isArray(e)||(e=gb);var h=v(e);h&1||$a(e);if(f)h&2||u(e,2),c&1||Object.freeze(e);else{f=!(c&2);var g=h&2;c&1||!g?f&&h&16&&!g&&Ua(e,16):(e=$a(Array.prototype.slice.call(e)),y(a,b,e,d))}return e}function yb(a,b){return xb(a,b,0,!1,w(a.i))}
+function B(a,b,c,d){var f=w(a.i),e=xb(a,b,1,d,f),h=v(e);if(!(h&4)){Object.isFrozen(e)&&(e=$a(e.slice()),y(a,b,e,d));for(var g=0,k=0;g<e.length;g++){var l=c(e[g]);null!=l&&(e[k++]=l)}k<g&&(e.length=k);u(e,5);f&&(u(e,2),Object.freeze(e))}!f&&(h&2||Object.isFrozen(e))&&(e=Array.prototype.slice.call(e),u(e,5),zb(a,b,e,d));return e}function Ub(a){return null==a?a:"string"===typeof a?a?new Ra(a,Ha):Sa():a.constructor===Ra?a:Ga(a)?a.length?new Ra(new Uint8Array(a),Ha):Sa():void 0}
+function E(a,b){a=x(a,b);return null==a?0:a}function zb(a,b,c,d){if(null==c)c=gb;else{var f=v(c);1!==(f&1)&&(Object.isFrozen(c)&&(c=Array.prototype.slice.call(c)),Va(c,f|1))}return wb(a,b,c,d)}function G(a,b,c,d){ib(a);c!==d?y(a,b,c):y(a,b,void 0,!1);return a}var Vb=Symbol(void 0);function Wb(a,b,c,d){var f=x(a,c,d);var e=!1;var h=null==f||"object"!==typeof f||(e=Array.isArray(f))||f.Y!==db?e?new b(f):void 0:f;h!==f&&null!=h&&(y(a,c,h,d),u(h.i,v(a.i)&-33));return h}
+function H(a,b,c){if(a=Wb(a,b,c,!1))b=a;else if(a=b[Vb])b=a;else{a=new b;if(wa!==wa)throw Error("requires a valid immutable API token");w(a.i)||((c=a.V)&&nb(c.i,a.i)?a=c:(c=Xb(a,!0),u(c.i,2),a=a.V=c));b=b[Vb]=a}return b}function J(a,b,c){var d=void 0===d?!1:d;b=Wb(a,b,c,d);if(null==b)return b;if(!w(a.i)){var f=Yb(b);f!==b&&(b=f,y(a,c,b,d))}return b}
+function Zb(a,b,c,d,f){a.o||(a.o={});var e=a.o[c],h=xb(a,c,3,void 0,f);if(e)f||(Object.isFrozen(e)?d||(e=Array.prototype.slice.call(e),a.o[c]=e):d&&Object.freeze(e));else{e=[];var g=!!(v(a.i)&16),k=w(h);!f&&k&&(h=$a(Array.prototype.slice.call(h)),y(a,c,h));for(var l=k,n=0;n<h.length;n++){var t=h[n];var I=b;var A=g,F=!1;F=void 0===F?!1:F;A=void 0===A?!1:A;I=Array.isArray(t)?new I(A?ab(t):t):F?new I:void 0;void 0!==I&&(l=l||w(t),e.push(I),k&&u(I.i,2))}a.o[c]=e;a=h;Object.isFrozen(a)||(b=v(a)|33,Va(a,
+l?b&-9:b|8));(f||d&&k)&&u(e,2);(f||d)&&Object.freeze(e)}return e}function K(a,b,c){var d=w(a.i);b=Zb(a,b,c,d,d);a=xb(a,c,3,void 0,d);if(!(d||v(a)&8)){for(d=0;d<b.length;d++){c=b[d];var f=Yb(c);c!==f&&(b[d]=f,a[d]=b[d].i)}u(a,8)}return b}function M(a,b,c){ib(a);null==c&&(c=void 0);return y(a,b,c)}function $b(a,b,c,d){ib(a);if(null!=c){var f=$a([]);for(var e=!1,h=0;h<c.length;h++)f[h]=c[h].i,e=e||w(f[h]);a.o||(a.o={});a.o[b]=c;c=f;e?Ua(c,8):u(c,8)}else a.o&&(a.o[b]=void 0),f=gb;return y(a,b,f,d)}
+function ac(a,b,c,d){ib(a);var f=Zb(a,c,b,!1,!1);c=null!=d?d:new c;a=xb(a,b,2,void 0,!1);f.push(c);a.push(c.i);w(c.i)&&Ua(a,8);return c}function N(a,b){return P(x(a,b),"0")}function P(a,b){return null==a?b:a}function R(a,b){a=x(a,b);return P(null==a?a:!!a,!1)}function S(a,b){a=x(a,b);return P(null==a?a:+a,0)}function T(a,b){return P(x(a,b),0)};function bc(a){var b=v(a);if(b&2)return a;a=xa(a,cc);cb(b,a);Object.freeze(a);return a}function dc(a,b,c){c=void 0===c?cb:c;if(null!=a){if(Ea&&a instanceof Uint8Array)return a.length?new Ra(new Uint8Array(a),Ha):Sa();if(Array.isArray(a)){var d=v(a);if(d&2)return a;if(b&&!(d&32)&&(d&16||0===d))return Va(a,d|2),a;a=sb(a,dc,c,!0);b=v(a);b&4&&b&2&&Object.freeze(a);return a}return a.Y===db?cc(a):a}}function cc(a){if(w(a.i))return a;a=Xb(a,!0);u(a.i,2);return a}
+function Xb(a,b){var c=a.i,d=ab([]),f=a.constructor.h;f&&d.push(f);0!==(v(c)&128)&&jb(d);b=b||w(a.i)?cb:bb;f=a.constructor;pb=d;d=new f(d);pb=void 0;a.ca&&(d.ca=a.ca.slice());f=!!(v(c)&16);for(var e=0;e<c.length;e++){var h=c[e];if(e===c.length-1&&eb(h))for(var g in h){var k=+g;if(Number.isNaN(k))vb(d)[k]=h[k];else{var l=h[g],n=a.o&&a.o[k];n?$b(d,k,bc(n),!0):wb(d,k,dc(l,f,b),!0)}}else k=e-a.H,(l=a.o&&a.o[k])?$b(d,k,bc(l),!1):wb(d,k,dc(h,f,b),!1)}return d}
+function Yb(a){if(!w(a.i))return a;var b=Xb(a,!1);b.V=a;return b};function V(a,b,c){null==a&&(a=pb);pb=void 0;var d=this.constructor.u||0,f=0<d,e=this.constructor.h,h=!1;if(null==a){a=e?[e]:[];var g=!0;Va(a,48)}else{if(!Array.isArray(a))throw Error();if(e&&e!==a[0])throw Error();var k=u(a,0),l=k;if(g=0!==(16&l))(h=0!==(32&l))||(l|=32);if(f)if(128&l)d=0;else{if(0<a.length){var n=a[a.length-1];if(eb(n)&&"g"in n){d=0;l|=128;delete n.g;var t=!0,I;for(I in n){t=!1;break}t&&a.pop()}}}else if(128&l)throw Error();k!==l&&Va(a,l)}this.H=(e?0:-1)-d;this.o=void 0;this.i=a;
+a:{e=this.i.length;d=e-1;if(e&&(e=this.i[d],eb(e))){this.h=e;this.u=d-this.H;break a}void 0!==b&&-1<b?(this.u=Math.max(b,d+1-this.H),this.h=void 0):this.u=Number.MAX_VALUE}if(!f&&this.h&&"g"in this.h)throw Error('Unexpected "g" flag in sparse object of message that is not a group type.');if(c){b=g&&!h&&!0;f=this.u;var A;for(g=0;g<c.length;g++)h=c[g],h<f?(h+=this.H,(d=a[h])?ec(d,b):a[h]=gb):(A||(A=vb(this)),(d=A[h])?ec(d,b):A[h]=gb)}}V.prototype.toJSON=function(){return sb(this.i,tb,ub)};
+function ec(a,b){if(Array.isArray(a)){var c=v(a),d=1;!b||c&2||(d|=16);(c&d)!==d&&Va(a,c|d)}}V.prototype.Y=db;V.prototype.toString=function(){return this.i.toString()};var fc=void 0;function gc(a){var b=fc;fc=void 0;if(!Array.isArray(a))throw b=b?b()+"\n":"",Error(b+String(a));return a};function hc(a){return JSON.stringify([a.map(function(b){var c={};return[(c[b.ta]=b.message.toJSON(),c)]})])};function ic(a){this.h=a}ic.prototype.sa=function(){var a=encodeURIComponent;var b=hc(sa.apply(0,arguments));for(var c=[],d=0,f=0;f<b.length;f++){var e=b.charCodeAt(f);255<e&&(c[d++]=e&255,e>>=8);c[d++]=e}b=Aa(c,3);a=a(b);this.h("https://pagead2.googlesyndication.com/pagead/ping?e=3&d="+a)};function jc(a){V.call(this,a)}q(jc,V);function kc(a){V.call(this,a)}q(kc,V);function lc(a){V.call(this,a,-1,mc)}q(lc,V);var mc=[6];function nc(a){V.call(this,a,-1,oc)}q(nc,V);var oc=[2,3,4];function pc(a){V.call(this,a,-1,qc)}q(pc,V);var qc=[2];function rc(a){V.call(this,a,-1,sc)}q(rc,V);var sc=[1,3,10,7,8];function tc(a){V.call(this,a)}q(tc,V);function uc(a){V.call(this,a,-1,vc)}q(uc,V);var vc=[3];function wc(a){V.call(this,a,-1,xc)}q(wc,V);var xc=[3];function yc(a){V.call(this,a,-1,zc)}q(yc,V);var zc=[2,3,5];function Ac(a){V.call(this,a,-1,Bc)}q(Ac,V);function Cc(a){V.call(this,a,-1,Dc)}q(Cc,V);function Ec(a){V.call(this,a,-1,Fc)}q(Ec,V);var Bc=[1,2],Dc=[3,4,9],Fc=[3,4,5,6,7];function Gc(a){V.call(this,a,-1,Hc)}q(Gc,V);var Hc=[15];function Ic(a){V.call(this,a)}q(Ic,V);function Jc(a){V.call(this,a,-1,Kc)}q(Jc,V);var Kc=[1];function Lc(a){V.call(this,a)}q(Lc,V);function Mc(a){V.call(this,a)}q(Mc,V);function Nc(a){V.call(this,a,-1,Oc)}q(Nc,V);var Oc=[9,10,11,12,13,14,15,17];function Pc(a){V.call(this,a,-1,Qc)}q(Pc,V);var Qc=[1];function Zd(a){V.call(this,a)}q(Zd,V);function $d(a){V.call(this,a,-1,ae)}q($d,V);function W(a){return J(a,be,3)}function ce(a){V.call(this,a,-1,de)}q(ce,V);function ee(a){V.call(this,a)}q(ee,V);function be(a){V.call(this,a)}q(be,V);function fe(a){V.call(this,a)}q(fe,V);function ge(a){V.call(this,a)}q(ge,V);function he(a){var b=new ge;return G(b,1,a,0)}function ie(a){V.call(this,a,-1,je)}q(ie,V);function ke(a){V.call(this,a)}q(ke,V);var ae=[2],de=[1,2,3],je=[1,3];function le(a){V.call(this,a,-1,me)}q(le,V);var me=[10];function ne(a){a.sa.apply(a,ja(sa.apply(1,arguments).map(function(b){return{ta:9,message:b}})))};function oe(a,b){return!b||0>=b?a:Math.min(a,b)}function X(a,b,c){return b?b:c?c:a?1:0}function pe(a,b){return a&&0<a.length?a:b&&0<b.length?b:[]}function qe(a){a=null==a?void 0:E(a,9);return void 0===a?!1:[61,51,52].includes(a)};function re(a,b){if(!b||0>=b)return{j:0,B:2};var c=null==a?void 0:J(a,ie,18),d,f=null==a?void 0:null==(d=W(a))?void 0:J(d,ie,11);d=null==a?void 0:J(a,fe,7);if(!c&&!f){var e;f=null==a?void 0:null==(e=W(a))?void 0:J(e,fe,4);e=X(!0,null==d?void 0:S(d,1),null==f?void 0:S(f,1));a=X(!1,null==d?void 0:S(d,2),null==f?void 0:S(f,2));c=X(!1,null==d?void 0:S(d,3),null==f?void 0:S(f,3));var h,g;d=X(!1,null==d?void 0:null==(h=J(d,ge,5))?void 0:S(h,1),null==f?void 0:null==(g=J(f,ge,5))?void 0:S(g,1));h=new fe;
+g=G(h,1,e,0);g=G(g,2,a,0);g=G(g,3,c,0);f=he(d);M(g,5,f);return{j:b*e*(1-1/(1+Math.exp(-a*(Math.log(b/1E6)-d-c)))),B:1,J:4,ba:h}}if(c||f){e=X(!1,null==c?void 0:S(c,2),null==f?void 0:S(f,2));a=pe(null==c?void 0:B(c,3,Number),null==f?void 0:B(f,3,Number));c=pe(null==c?void 0:yb(c,1),null==f?void 0:yb(f,1));h=[];g=p(c);for(f=g.next();!f.done;f=g.next())switch(f.value){case 1:h.push(1E-6*b);break;case 2:var k=f=void 0,l=null==(f=d)?void 0:null==(k=J(f,ge,5))?void 0:S(k,1);h.push("number"===typeof l?Math.exp(l):
+0)}d=se(a,h);1===d.B?(b=new ie,b=zb(b,3,a),b=zb(b,1,c),b=G(b,2,e,0),d.ba=b,b=d):b=0>=e||1<e?d:{j:b*e,B:d.B,J:9}}else b={j:0,B:3};return b}
+function se(a,b){if(0===a.length||0>a[0])return{j:0,B:5};var c=b.length;if(a.length!==1+2*(1+c))return{j:0,B:6};for(var d=c+2,f=a[1],e=a[d],h=0;h<c;h++){var g=1+h;if(0>=b[h]){if(1E-9>Math.abs(a[1+g])&&1E-9>Math.abs(a[d+g]))continue;return{j:0,B:4}}var k=Math.log(b[h]);f+=a[1+g]*k;e+=a[d+g]*k}return{j:1E9*Math.exp(-.5*(-(f+e)+Math.sqrt((f-e)*(f-e)+4*a[0]))),B:1,J:8}};function te(a,b){var c=null==a?void 0:J(a,fe,6),d,f=null==a?void 0:null==(d=W(a))?void 0:J(d,fe,3);if(!b||0>=b)return{j:0,J:1};if(1===(null==a?void 0:T(a,17)))return{j:b,J:2};var e;if(!(null==a?0:null==(e=W(a))?0:R(e,2)))return{j:.85*b,J:2};d=X(!0,null==c?void 0:S(c,4),null==f?void 0:S(f,4));e=X(!0,null==c?void 0:S(c,1),null==f?void 0:S(f,1));var h=X(!1,null==c?void 0:S(c,2),null==f?void 0:S(f,2)),g=X(!1,null==c?void 0:S(c,3),null==f?void 0:S(f,3)),k,l,n=X(!1,null==c?void 0:null==(k=J(c,ge,5))?void 0:
+S(k,1),null==f?void 0:null==(l=J(f,ge,5))?void 0:S(l,1));l=X(!1,null==c?void 0:S(c,9),null==f?void 0:S(f,9));k=new fe;var t=G(k,1,e,0);t=G(t,2,h,0);t=G(t,3,g,0);t=G(t,4,d,0);t=G(t,9,l,0);var I=he(n);M(t,5,I);t=3;d=d*b*e*(1-1/(1+Math.exp(-h*(Math.log(d*b/1E6)-n-g))));d<l*b&&(d=l*b,t=6);e=1E6*(null==a?NaN:S(a,8));var A;c=null!=(A=null==c?void 0:S(c,8))?A:0;var F;if((null==a?0:null==(F=W(a))?0:R(F,6))&&d<e&&e<b){var O;a=null!=(O=null==f?void 0:S(f,7))?O:0;d=e+a*(0===c?Math.log(b/e):(b-e)/(c-e))*1E6;
+t=7}return{j:d,J:t,ba:k}};function ue(a,b){if(!(0<B(a,2,Number).length&&B(a,2,Number).length===yb(a,3).length&&B(a,2,Number).length===B(a,4,Number).length))return 0;for(var c=0,d=0,f=1,e=p(yb(a,3)),h=e.next();!h.done;h=e.next()){var g=0;switch(h.value){case 1:g=B(a,2,Number)[d]*(b.M?Math.pow(b.M,B(a,4,Number)[d]):0);break;case 2:c=g=B(a,2,Number)[d]*(b.X?Math.pow(b.X,B(a,4,Number)[d]):0);break;case 3:g=B(a,2,Number)[d]}if(0===g)return 0;f*=g;d+=1}0<S(a,7)&&(f=Math.min(f,S(a,7)*c*1E3));return 1E6*f}
+function ve(a,b){var c=0;b&&(0<K(b,nc,7).length?c=ue(K(b,nc,7)[0],a):0<K(b,nc,8).length&&(c=ue(K(b,nc,8)[0],a)));return c};var we={Ga:0,Ca:1,xa:2,za:3,ya:4,Da:5,Ea:6,Ha:7,Ba:8,va:9,Fa:10,Aa:11,wa:12};function xe(a,b,c){if(E(a,2)!==E(b,2))return c;var d=!1;switch(E(a,2)){case 1:a:{var f,e=new Set(null!=(f=yb(a,3))?f:[]);b=p(yb(b,3));for(f=b.next();!f.done;f=b.next())if(e.has(f.value)){d=!0;break a}d=!1}break;case 0:a:{f=new Set(null!=(e=B(a,4,lb,!1))?e:[]);b=p(B(b,4,lb,!1));for(e=b.next();!e.done;e=b.next())if(f.has(e.value)){d=!0;break a}d=!1}break;case 2:b=new ye(b);d=(f=J(a,yc,5))?ze(b,f):!1;break;case 3:a:{f=new Set;e=p(B(a,9,Ub));for(d=e.next();!d.done;d=e.next())f.add(Ta(d.value));if(0===
+f.size)d=!0;else{b=p(B(b,6,Ub));for(e=b.next();!e.done;e=b.next())if(f.has(Ta(e.value))){d=!0;break a}d=!1}}break;case 4:d=Ae(a,b)}return R(a,6)?d?null:c:d?c:null}
+function Ae(a,b){a=J(a,uc,10);if(void 0===a)return!1;var c=K(b,wc,7);if(0===c.length)return!1;b=!0;c=p(c);for(var d=c.next();!d.done;d=c.next())if(d=d.value,T(d,1)===T(a,1)&&T(d,2)===T(a,2)){b&&(b=!1);var f=yb(d,3);if(0===f.length)return!1;d=!0;f=p(f);for(var e=f.next();!e.done;e=f.next()){e=e.value;var h=Math.floor(e/32),g=yb(a,3);if(!(h>=g.length||0!==(g[h]>>>e%32)%2)){d=!1;break}}if(d)return!0}return b}
+function ze(a,b){var c=E(b,1),d=K(b,tc,3),f=K(b,yc,2);switch(c){case 2:c=d.every(function(e){return Be(a,e)})&&f.every(function(e){return ze(a,e)});break;case 1:c=d.some(function(e){return Be(a,e)})||f.some(function(e){return ze(a,e)});break;default:throw Error("unexpected value "+c+"!");}return R(b,4)?!c:c}function ye(a){this.h=new Map;a=p(K(a,tc,5));for(var b=a.next();!b.done;b=a.next()){var c=b.value;b=P(x(c,1),0);c=P(x(c,2),0);var d=this.h.get(b);d||(d=new Set,this.h.set(b,d));d.add(c)}}
+function Be(a,b){var c=P(x(b,2),0);return(a=a.h.get(P(x(b,1),0)))?a.has(c):!1};function Ce(a,b){a=p((null==b?void 0:b.get(a))||[]);for(b=a.next();!b.done;b=a.next())if(b=b.value,b.count+1>b.ra)return!1;return!0};function De(a){a=a.split("!");for(var b="-1",c=0;c<a.length;c++)a[c].match(/^\dm\d+/)?c+=+a[c].substring(2):a[c].match(/^\d{2}m\d+/)?c+=+a[c].substring(3):a[c].match(/^1j\d+/)&&(b=a[c].substring(2));return b}
+function Ee(a,b){if(!a.pa)return 1;var c,d=null==(c=a.da)?void 0:c.some(function(h){var g;return null==(g=b.ga)?void 0:g.includes(h,0)}),f;c=null!=(f=b.interestGroupName)?f:void 0;if(void 0===c)return 10;f=De(c);if("-1"===f)return 11;var e;a=null==(e=a.da)?void 0:e.includes(f,0);return d&&!a?10:1};function Fe(a,b){return null==a.Z?!0:!a.Z.some(function(c){var d;return null==(d=b.ga)?void 0:d.includes(c,0)})};function Ge(a,b){return He(0,(null==a?void 0:K(a,pc,1))||[],(null==b?void 0:K(b,pc,1))||[])}function Ie(a,b){return He(1,(null==a?void 0:K(a,pc,2))||[],(null==b?void 0:K(b,pc,3))||[])}function Je(a,b){return He(1,(null==a?void 0:K(a,pc,3))||[],(null==b?void 0:K(b,pc,3))||[])}
+function He(a,b,c){var d=0,f=new Map;b=p(b);for(var e=b.next();!e.done;e=b.next())d=e.value,f.set(P(x(d,1),""),d),d=S(d,3);b=null;c=p(c);for(e=c.next();!e.done;e=c.next()){var h=e.value;d=S(h,3);if(e=f.get(P(x(h,1),""))){a:{b=a;e=B(e,2,Number);h=B(h,2,Number);if(e.length===h.length){for(var g=0,k=0;k<e.length;k++)g+=e[k]*h[k];e=g}else e=void 0;if(void 0!==e)switch(b){case 0:b=1/(1+Math.exp(-1*e));break a;case 1:b=Math.exp(e);break a}b=void 0}if(void 0!==b)return b;b=d}}var l;return null!=(l=b)?l:
+d};function Ke(a,b,c){"0"===a||c.has(a)||c.set(a,b.filter(function(d){return 0<T(d,3)}).map(function(d){var f=T(d,3);switch(E(d,1)){case 6:d=60*T(d,2);break;case 1:d=3600*T(d,2);break;case 2:d=86400*T(d,2);break;case 3:d=604800*T(d,2);break;case 4:d=2592E3*T(d,2);break;case 5:d=null;break;default:f=d=0}return{fa:d,ra:f,count:0}}))}function Le(a,b,c){if(b=c.get(b))for(b=p(b),c=b.next();!c.done;c=b.next())c=c.value,(null===c.fa||T(a,1)<=c.fa)&&c.count++};function Me(a){V.call(this,a,-1,Ne)}q(Me,V);var Ne=[1];var Oe={ad:{},bid:0,render:"",allowComponentAuction:!0};function Pe(){new Me;return function(a,b,c,d,f){return Qe(a,c,d,f)}}
+function Qe(a,b,c,d){b=b?new $d(gc(b)):void 0;var f,e;if(!b||!(K(b,ee,2).length||(null==(f=W(b))?0:R(f,1))||(null==(e=W(b))?0:R(e,5))))return Oe;f=new Jc(gc(a.userBiddingSignals));e=a.ads.map(function(g){return{renderUrl:g.renderUrl,metadata:new jc(gc(g.metadata))}});c=c[a.name]?new Pc(gc(c[a.name])):void 0;var h=d.prevWins.map(function(g){var k=new kc;k=G(k,1,g[0],0);g=new jc(gc(g[1].metadata));return M(k,2,g)});return Re(a.name,f,e,d,h,c,b)}
+function Re(a,b,c,d,f,e,h){var g=null,k=null,l=null;if(h&&(R(H(h,Zd,12),1)||R(H(h,Zd,12),2))){var n=new le;var t=G(n,2,0,0);var I=G(t,5,a,"");var A=G(I,7,!1,!1);var F=M(A,8,h);g=G(F,9,P(x(h,4),""),"");var O=globalThis.forDebuggingOnly;R(H(h,Zd,12),1)&&(k=new ic(O.reportAdAuctionWin));R(H(h,Zd,12),2)&&(l=new ic(O.reportAdAuctionLoss));if(R(H(h,Zd,12),5)){var Wa=M(g,6,b),ea=new lc;var Xa=G(ea,1,d.topWindowHostname,"");var Y=G(Xa,2,d.seller,"");var Q=G(Y,3,d.topLevelSeller,"");var We=G(Q,4,d.joinCount,
+0);var Xe=G(We,5,d.bidCount,0);var Ye=$b(Xe,6,f);var Ze=G(Ye,7,d.dataVersion,0);M(Wa,11,Ze);e&&M(g,3,e)}}var Ya=g,Rc,D={ea:null!=(Rc=null==h?void 0:W(h))?Rc:void 0,T:new Map,N:new Map,O:new Map,P:new Map,W:new Map,interestGroupName:null!=a?a:void 0,ua:E(b,2),ia:d.joinCount},ka=new Map;if(e){for(var Sc=p(K(e,Nc,1)),Ab=Sc.next();!Ab.done;Ab=Sc.next()){var L=Ab.value,$e=Se(N(L,1),N(L,2),N(L,3));ka.set($e,L);Ke(N(L,2),K(L,Lc,9),D.T);Ke(N(L,1),K(L,Lc,10),D.N);Ke(N(L,6),K(L,Lc,11),D.O);Ke(N(L,7),K(L,Lc,
+12),D.P);Ke(N(L,8),K(L,Lc,13),D.W)}for(var Tc=p(f),Bb=Tc.next();!Bb.done;Bb=Tc.next()){var Z=Bb.value;D.T&&Le(Z,N(H(Z,jc,2),2),D.T);D.N&&Le(Z,N(H(Z,jc,2),1),D.N);D.O&&Le(Z,N(H(Z,jc,2),4),D.O);D.P&&Le(Z,N(H(Z,jc,2),5),D.P);D.W&&Le(Z,N(H(Z,jc,2),6),D.W)}}var Uc=new Map;if(h)for(var Vc=p(K(h,ee,2)),Cb=Vc.next();!Cb.done;Cb=Vc.next()){var Db=Cb.value,af=Se(N(Db,1),N(Db,2),"");Uc.set(af,S(Db,3))}for(var Wc=[],Xc=p(c),Eb=Xc.next();!Eb.done;Eb=Xc.next()){var U=Eb.value,z={renderUrl:U.renderUrl,D:N(U.metadata,
+1),G:N(U.metadata,2),L:N(U.metadata,3),S:N(U.metadata,4),R:N(U.metadata,5),U:N(U.metadata,6),ja:N(U.metadata,7),ka:N(U.metadata,8),la:N(U.metadata,9),ma:N(U.metadata,10),l:0,I:0},pa=Se(z.D,z.G,z.L);z.K=Uc.get(Se(z.D,z.G,""));if(!z.K){var Yc=void 0,Zc=void 0,$c=void 0,ad=void 0;if(!(null==(Yc=h)?0:null==(Zc=W(Yc))?0:R(Zc,1))&&!(null==($c=h)?0:null==(ad=W($c))?0:R(ad,5))){Ya&&Te(Ya,z,5,1);continue}else if(!ka.get(pa)){Ya&&Te(Ya,z,6,1);continue}var bd=void 0,cd=void 0;z.v=null!=(cd=null==(bd=ka.get(pa))?
+void 0:J(bd,rc,4))?cd:void 0}var dd=void 0,ed=void 0;z.F=null!=(ed=null==(dd=ka.get(pa))?void 0:J(dd,Ac,5))?ed:void 0;var fd=void 0,gd=void 0,hd=null!=(gd=null==(fd=ka.get(pa))?void 0:K(fd,Mc,17))?gd:void 0;if(hd)for(var id=p(hd),Fb=id.next();!Fb.done;Fb=id.next()){var Ja=Fb.value;if(z.ja===N(Ja,1)&&z.ka===N(Ja,2)&&z.la===N(Ja,3)&&z.ma===N(Ja,4)){z.F||(z.F=new Ac);var Gb=J(Ja,Ac,5);if(Gb){for(var jd=p(K(Gb,Cc,1)),Hb=jd.next();!Hb.done;Hb=jd.next())ac(z.F,1,Cc,Hb.value);for(var kd=p(K(Gb,Ec,2)),Ib=
+kd.next();!Ib.done;Ib=kd.next())ac(z.F,2,Ec,Ib.value)}}}var ld=void 0,md=void 0;z.Z=null!=(md=null==(ld=ka.get(pa))?void 0:B(ld,14,kb))?md:void 0;var nd=void 0,od=void 0;z.da=null!=(od=null==(nd=ka.get(pa))?void 0:B(nd,15,kb))?od:void 0;var pd=void 0,qd=void 0;z.pa=null!=(qd=null==(pd=ka.get(pa))?void 0:R(pd,16))?qd:!1;Wc.push(z)}var Jb=null==h?void 0:J(h,Ac,5);if(Jb){for(var rd=new Map,sd=new Map,td=p(K(Jb,Cc,1)),Kb=td.next();!Kb.done;Kb=td.next()){var ud=Kb.value;rd.set(E(ud,1),ud)}for(var vd=p(K(Jb,
+Ec,2)),Lb=vd.next();!Lb.done;Lb=vd.next()){var wd=Lb.value;sd.set(E(wd,1),wd)}D.na=rd;D.oa=sd}var xd;D.ga=null!=(xd=B(b,1,kb))?xd:void 0;var ha={ads:Wc,signals:D};var Za=ha.signals;if(1!==Za.ua)var Mb=!0;else{var yd;if(null!=(yd=Za.ea)&&R(yd,8)){var zd;Mb=Za.ia<(null==(zd=Za.ea)?void 0:T(zd,9))?!1:!0}else Mb=!1}var Nb=Mb?1:8;if(1!==Nb&&null!==g)for(var Ad=p(ha.ads),Ob=Ad.next();!Ob.done;Ob=Ad.next())Te(g,Ob.value,Nb,2);var Bd=Oe,Cd=ha;if(1===Nb){for(var aa=g,Dd=null==h?void 0:W(h),Ed=[],Fd=new Map,
+Gd=p(ha.ads),Pb=Gd.next();!Pb.done;Pb=Gd.next()){var C=Pb.value,Hd=void 0;if(void 0!==Dd&&(null==(Hd=Dd)?0:R(Hd,10))&&(C.renderUrl.includes("/td/adfetch/dv3")||qe(C.v)))aa&&Te(aa,C,12,3);else{var Ka=ha.signals;if(!Ce(C.G,Ka.T)||!Ce(C.D,Ka.N)||C.S&&!Ce(C.S,Ka.O)||C.R&&!Ce(C.R,Ka.P)||C.U&&!Ce(C.U,Ka.W))aa&&Te(aa,C,3,3);else{if(C.F){var Id=ha.signals,Jd=Id.na,Kd=Id.oa,Ld=C.F;if(Jd&&Kd&&Ld)a:{for(var bf=Jd,cf=Kd,Md=Ld,Nd=p(K(Md,Cc,1)),Qb=Nd.next();!Qb.done;Qb=Nd.next()){var La=Qb.value,Ma=E(La,1),Rb=
+cf.get(Ma);if(Rb){var Na=null;if(R(La,7)){var Oa=Fd.get(Ma),Od=!0,Pd=P(x(La,8),0);if(void 0===Oa)Oa=new Map,Fd.set(Ma,Oa);else{var Sb=Oa.get(Pd);if(Sb){var Pa=Sb;break a}null===Sb&&(Od=!1)}Od&&(Na=xe(La,Rb,Ma),Oa.set(Pd,Na))}else Na=xe(La,Rb,Ma);if(Na){Pa=Na;break a}}}for(var Qd=p(K(Md,Ec,2)),Tb=Qd.next();!Tb.done;Tb=Qd.next()){var Rd=Tb.value,Sd=E(Rd,1),Td=bf.get(Sd);if(Td){var Ud=xe(Td,Rd,Sd);if(Ud){Pa=Ud;break a}}}Pa=null}else Pa=null;var Vd=Pa;if(Vd){aa&&Te(aa,C,4,3,Vd);continue}}if(Fe(C,ha.signals)){var Wd=
+Ee(C,ha.signals);1!==Wd?aa&&Te(aa,C,Wd,3):Ed.push(C)}else aa&&Te(aa,C,7,3)}}}Cd={ads:Ed,signals:ha.signals};Bd=Ue(Cd,g,h).ha}if(void 0!==h&&null!==g){if(k){var Xd=g,ef=k;G(Xd,2,1,0);ne(ef,Xd)}if(l){var Yd=g,ff=l;G(Yd,2,2,0);ne(ff,Yd)}}return Bd}
+function Te(a,b,c,d,f){a=ac(a,10,Ic);d=G(a,3,d,0);var e;var h=new Gc;h=G(h,1,b.renderUrl,"");h=G(h,2,b.D,"");h=G(h,3,b.G,"");h=G(h,4,b.L,"");h=G(h,12,b.l,0);h=G(h,13,b.I,0);var g=null!=(e=b.qa)?e:!1;e=G(h,16,g,!1);void 0!==b.S&&G(e,5,b.S,"");void 0!==b.R&&G(e,6,b.R,"");void 0!==b.U&&G(e,7,b.U,"");void 0!==b.v&&M(e,8,b.v);void 0!==b.X&&G(e,9,b.X,0);void 0!==b.M&&G(e,10,b.M,0);void 0!==b.K&&G(e,11,b.K,0);void 0!==b.F&&M(e,14,b.F);var k;b=p(null!=(k=b.Z)?k:[]);for(h=b.next();!h.done;h=b.next())k=e,h=
+h.value,ib(k),xb(k,15,2,!1,!1).push(h);M(d,1,e);void 0!==f&&G(a,5,f,0);Object.values(we).includes(c)&&G(a,2,c,0)}
+function Ue(a,b,c){for(var d=[],f=[],e=p(a.ads),h=e.next();!h.done;h=e.next())if(h=h.value,null!=h.K)h.l=h.K,h.qa=!0,d.push(h);else{var g=void 0,k=void 0;if(null==(g=c)?0:null==(k=W(g))?0:R(k,1))qe(h.v)?(g=void 0,h.M=Je(null==(g=c)?void 0:J(g,ce,1),h.v)):(g=void 0,h.X=Ge(null==(g=c)?void 0:J(g,ce,1),h.v),g=void 0,h.M=Ie(null==(g=c)?void 0:J(g,ce,1),h.v)),h.l=ve(h,h.v),h.l||(k=g=void 0,h.l=null!=(k=null==(g=h.v)?void 0:S(g,6))?k:0);else if(k=g=void 0,null==(g=c)?0:null==(k=W(g))?0:R(k,5))k=g=void 0,
+h.l=null!=(k=null==(g=h.v)?void 0:S(g,6))?k:0;k=g=void 0;if(null==(g=c)?0:null==(k=W(g))?0:R(k,7)){var l=k=g=void 0,n=void 0,t=void 0,I=void 0;if(h.D===(null==(g=c)?void 0:null==(k=J(g,ke,16))?void 0:N(k,2))&&h.G===(null==(l=c)?void 0:null==(n=J(l,ke,16))?void 0:N(n,3))&&a.signals.interestGroupName===(null==(t=c)?void 0:null==(I=J(t,ke,16))?void 0:P(x(I,1),""))){if(k=g=void 0,null==(g=c)?0:null==(k=J(g,ke,16))?0:R(k,7))l=k=g=void 0,n=null!=(l=null==(g=c)?void 0:null==(k=J(g,ke,16))?void 0:S(k,5))?
+l:0,h.l=0===n?1:n}else h.l=0}f.push(h)}d={renderUrl:"",D:"",G:"",L:"",l:0,I:0};var A,F;if((null==c?0:null==(A=W(c))?0:R(A,7))&&(null==c?0:null==(F=J(c,ke,16))?0:R(F,7)))c=a.ads.reduce(function(Y,Q){return Y.l<Q.l?Q:Y},d),c.I=c.l;else{A=a.ads.reduce(function(Y,Q){return!qe(Q.v)&&Y.l<Q.l?Q:Y},d);d=a.ads.reduce(function(Y,Q){return qe(Q.v)&&Y.l<Q.l?Q:Y},d);F=te(c,null==A?void 0:A.l);var O,Wa;F.j=oe(F.j,null==c?void 0:null==(O=W(c))?void 0:null==(Wa=J(O,fe,3))?void 0:S(Wa,6));O=re(c,null==d?void 0:d.l);
+var ea,Xa;O.j=oe(O.j,null==c?void 0:null==(ea=W(c))?void 0:null==(Xa=J(ea,fe,4))?void 0:S(Xa,6));F.j>O.j?(c=A,c.I=F.j):(c=d,c.I=O.j)}if(b)for(a=p(a.ads),h=a.next();!h.done;h=a.next())ea=h.value,Te(b,ea,Se(ea.D,ea.G,ea.L)===Se(c.D,c.G,c.L)?1:9,4);return{ha:{ad:{},bid:c.I/1E6,render:c.renderUrl,allowComponentAuction:!0},debugInfo:void 0}}function Se(a,b,c){return a.concat("+",b,"+",c)};function Ve(a,b,c,d,f){a={renderUrl:a.render_uri,metadata:a.metadata.metadata};f={owner:f.owner,name:f.name,biddingLogicUrl:"",userBiddingSignals:f.user_bidding_signals.signals,ads:[a]};a={topWindowHostname:"",seller:"",joinCount:0,bidCount:0,prevWins:[[0,a]]};b=Pe()(f,b,c.signals,d,a);c="";"string"===typeof b.render?c=b.render:(d=b.render,0<d.length&&(c=d[0]));return{status:0,ad:{render_uri:c,metadata:b.ad},bid:b.bid}};var df=globalThis;df.generateBid=function(a,b,c,d,f,e){return Ve(a,b,c,d,e)};df.generateBidIterative=function(a,b,c,d,f,e){f=(new Date).getTime();var h=[];a=p(a);for(var g=a.next();!g.done;g=a.next())g=Ve(g.value,b,c,d,e),h.push(g);return{responses:h,status:0,duration:(new Date).getTime()-f}};
diff --git a/apct-tests/perftests/rubidium/assets/rubidium_scoring_logic_compiled.js b/apct-tests/perftests/rubidium/assets/rubidium_scoring_logic_compiled.js
new file mode 100644
index 000000000000..406a45dc5e0e
--- /dev/null
+++ b/apct-tests/perftests/rubidium/assets/rubidium_scoring_logic_compiled.js
@@ -0,0 +1,59 @@
+/*
+
+ Copyright The Closure Library Authors.
+ SPDX-License-Identifier: Apache-2.0
+*/
+'use strict';function aa(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}}var ba="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};
+function ca(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var ea=ca(this);function n(a,b){if(b)a:{var c=ea;a=a.split(".");for(var d=0;d<a.length-1;d++){var f=a[d];if(!(f in c))break a;c=c[f]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&ba(c,a,{configurable:!0,writable:!0,value:b})}}
+n("Symbol",function(a){function b(e){if(this instanceof b)throw new TypeError("Symbol is not a constructor");return new c(d+(e||"")+"_"+f++,e)}function c(e,g){this.h=e;ba(this,"description",{configurable:!0,writable:!0,value:g})}if(a)return a;c.prototype.toString=function(){return this.h};var d="jscomp_symbol_"+(1E9*Math.random()>>>0)+"_",f=0;return b});
+n("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c<b.length;c++){var d=ea[b[c]];"function"===typeof d&&"function"!=typeof d.prototype[a]&&ba(d.prototype,a,{configurable:!0,writable:!0,value:function(){return fa(aa(this))}})}return a});function fa(a){a={next:a};a[Symbol.iterator]=function(){return this};return a}
+function p(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):{next:aa(a)}}function ha(a){if(!(a instanceof Array)){a=p(a);for(var b,c=[];!(b=a.next()).done;)c.push(b.value);a=c}return a}var ia="function"==typeof Object.create?Object.create:function(a){function b(){}b.prototype=a;return new b},ja;
+if("function"==typeof Object.setPrototypeOf)ja=Object.setPrototypeOf;else{var ka;a:{var la={a:!0},ma={};try{ma.__proto__=la;ka=ma.a;break a}catch(a){}ka=!1}ja=ka?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}var na=ja;
+function r(a,b){a.prototype=ia(b.prototype);a.prototype.constructor=a;if(na)na(a,b);else for(var c in b)if("prototype"!=c)if(Object.defineProperties){var d=Object.getOwnPropertyDescriptor(b,c);d&&Object.defineProperty(a,c,d)}else a[c]=b[c];a.la=b.prototype}function oa(){for(var a=Number(this),b=[],c=a;c<arguments.length;c++)b[c-a]=arguments[c];return b}function t(a,b){return Object.prototype.hasOwnProperty.call(a,b)}
+n("WeakMap",function(a){function b(k){this.h=(h+=Math.random()+1).toString();if(k){k=p(k);for(var l;!(l=k.next()).done;)l=l.value,this.set(l[0],l[1])}}function c(){}function d(k){var l=typeof k;return"object"===l&&null!==k||"function"===l}function f(k){if(!t(k,g)){var l=new c;ba(k,g,{value:l})}}function e(k){var l=Object[k];l&&(Object[k]=function(m){if(m instanceof c)return m;Object.isExtensible(m)&&f(m);return l(m)})}if(function(){if(!a||!Object.seal)return!1;try{var k=Object.seal({}),l=Object.seal({}),
+m=new a([[k,2],[l,3]]);if(2!=m.get(k)||3!=m.get(l))return!1;m.delete(k);m.set(l,4);return!m.has(k)&&4==m.get(l)}catch(q){return!1}}())return a;var g="$jscomp_hidden_"+Math.random();e("freeze");e("preventExtensions");e("seal");var h=0;b.prototype.set=function(k,l){if(!d(k))throw Error("Invalid WeakMap key");f(k);if(!t(k,g))throw Error("WeakMap key fail: "+k);k[g][this.h]=l;return this};b.prototype.get=function(k){return d(k)&&t(k,g)?k[g][this.h]:void 0};b.prototype.has=function(k){return d(k)&&t(k,
+g)&&t(k[g],this.h)};b.prototype.delete=function(k){return d(k)&&t(k,g)&&t(k[g],this.h)?delete k[g][this.h]:!1};return b});
+n("Map",function(a){function b(){var h={};return h.v=h.next=h.head=h}function c(h,k){var l=h.h;return fa(function(){if(l){for(;l.head!=h.h;)l=l.v;for(;l.next!=l.head;)return l=l.next,{done:!1,value:k(l)};l=null}return{done:!0,value:void 0}})}function d(h,k){var l=k&&typeof k;"object"==l||"function"==l?e.has(k)?l=e.get(k):(l=""+ ++g,e.set(k,l)):l="p_"+k;var m=h.i[l];if(m&&t(h.i,l))for(h=0;h<m.length;h++){var q=m[h];if(k!==k&&q.key!==q.key||k===q.key)return{id:l,list:m,index:h,l:q}}return{id:l,list:m,
+index:-1,l:void 0}}function f(h){this.i={};this.h=b();this.size=0;if(h){h=p(h);for(var k;!(k=h.next()).done;)k=k.value,this.set(k[0],k[1])}}if(function(){if(!a||"function"!=typeof a||!a.prototype.entries||"function"!=typeof Object.seal)return!1;try{var h=Object.seal({x:4}),k=new a(p([[h,"s"]]));if("s"!=k.get(h)||1!=k.size||k.get({x:4})||k.set({x:4},"t")!=k||2!=k.size)return!1;var l=k.entries(),m=l.next();if(m.done||m.value[0]!=h||"s"!=m.value[1])return!1;m=l.next();return m.done||4!=m.value[0].x||
+"t"!=m.value[1]||!l.next().done?!1:!0}catch(q){return!1}}())return a;var e=new WeakMap;f.prototype.set=function(h,k){h=0===h?0:h;var l=d(this,h);l.list||(l.list=this.i[l.id]=[]);l.l?l.l.value=k:(l.l={next:this.h,v:this.h.v,head:this.h,key:h,value:k},l.list.push(l.l),this.h.v.next=l.l,this.h.v=l.l,this.size++);return this};f.prototype.delete=function(h){h=d(this,h);return h.l&&h.list?(h.list.splice(h.index,1),h.list.length||delete this.i[h.id],h.l.v.next=h.l.next,h.l.next.v=h.l.v,h.l.head=null,this.size--,
+!0):!1};f.prototype.clear=function(){this.i={};this.h=this.h.v=b();this.size=0};f.prototype.has=function(h){return!!d(this,h).l};f.prototype.get=function(h){return(h=d(this,h).l)&&h.value};f.prototype.entries=function(){return c(this,function(h){return[h.key,h.value]})};f.prototype.keys=function(){return c(this,function(h){return h.key})};f.prototype.values=function(){return c(this,function(h){return h.value})};f.prototype.forEach=function(h,k){for(var l=this.entries(),m;!(m=l.next()).done;)m=m.value,
+h.call(k,m[1],m[0],this)};f.prototype[Symbol.iterator]=f.prototype.entries;var g=0;return f});n("Number.isNaN",function(a){return a?a:function(b){return"number"===typeof b&&isNaN(b)}});function pa(a,b){a instanceof String&&(a+="");var c=0,d=!1,f={next:function(){if(!d&&c<a.length){var e=c++;return{value:b(e,a[e]),done:!1}}d=!0;return{done:!0,value:void 0}}};f[Symbol.iterator]=function(){return f};return f}n("Array.prototype.values",function(a){return a?a:function(){return pa(this,function(b,c){return c})}});
+n("Set",function(a){function b(c){this.h=new Map;if(c){c=p(c);for(var d;!(d=c.next()).done;)this.add(d.value)}this.size=this.h.size}if(function(){if(!a||"function"!=typeof a||!a.prototype.entries||"function"!=typeof Object.seal)return!1;try{var c=Object.seal({x:4}),d=new a(p([c]));if(!d.has(c)||1!=d.size||d.add(c)!=d||1!=d.size||d.add({x:4})!=d||2!=d.size)return!1;var f=d.entries(),e=f.next();if(e.done||e.value[0]!=c||e.value[1]!=c)return!1;e=f.next();return e.done||e.value[0]==c||4!=e.value[0].x||
+e.value[1]!=e.value[0]?!1:f.next().done}catch(g){return!1}}())return a;b.prototype.add=function(c){c=0===c?0:c;this.h.set(c,c);this.size=this.h.size;return this};b.prototype.delete=function(c){c=this.h.delete(c);this.size=this.h.size;return c};b.prototype.clear=function(){this.h.clear();this.size=0};b.prototype.has=function(c){return this.h.has(c)};b.prototype.entries=function(){return this.h.entries()};b.prototype.values=function(){return this.h.values()};b.prototype.keys=b.prototype.values;b.prototype[Symbol.iterator]=
+b.prototype.values;b.prototype.forEach=function(c,d){var f=this;this.h.forEach(function(e){return c.call(d,e,e,f)})};return b});n("globalThis",function(a){return a||ea});n("Object.values",function(a){return a?a:function(b){var c=[],d;for(d in b)t(b,d)&&c.push(b[d]);return c}});n("Object.is",function(a){return a?a:function(b,c){return b===c?0!==b||1/b===1/c:b!==b&&c!==c}});
+n("Array.prototype.includes",function(a){return a?a:function(b,c){var d=this;d instanceof String&&(d=String(d));var f=d.length;c=c||0;for(0>c&&(c=Math.max(c+f,0));c<f;c++){var e=d[c];if(e===b||Object.is(e,b))return!0}return!1}});
+n("String.prototype.includes",function(a){return a?a:function(b,c){if(null==this)throw new TypeError("The 'this' value for String.prototype.includes must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype.includes must not be a regular expression");return-1!==this.indexOf(b,c||0)}});function qa(a){var b=typeof a;return"object"==b&&null!=a||"function"==b};var ra={};var sa=Array.prototype.map?function(a,b){return Array.prototype.map.call(a,b,void 0)}:function(a,b){for(var c=a.length,d=Array(c),f="string"===typeof a?a.split(""):a,e=0;e<c;e++)e in f&&(d[e]=b.call(void 0,f[e],e,a));return d};var ta={},u=null;function ua(a,b){void 0===b&&(b=0);va();b=ta[b];for(var c=Array(Math.floor(a.length/3)),d=b[64]||"",f=0,e=0;f<a.length-2;f+=3){var g=a[f],h=a[f+1],k=a[f+2],l=b[g>>2];g=b[(g&3)<<4|h>>4];h=b[(h&15)<<2|k>>6];k=b[k&63];c[e++]=l+g+h+k}l=0;k=d;switch(a.length-f){case 2:l=a[f+1],k=b[(l&15)<<2]||d;case 1:a=a[f],c[e]=b[a>>2]+b[(a&3)<<4|l>>4]+k+d}return c.join("")}
+function wa(a){var b=a.length,c=3*b/4;c%3?c=Math.floor(c):-1!="=.".indexOf(a[b-1])&&(c=-1!="=.".indexOf(a[b-2])?c-2:c-1);var d=new Uint8Array(c),f=0;xa(a,function(e){d[f++]=e});return f!==c?d.subarray(0,f):d}
+function xa(a,b){function c(k){for(;d<a.length;){var l=a.charAt(d++),m=u[l];if(null!=m)return m;if(!/^[\s\xa0]*$/.test(l))throw Error("Unknown base64 encoding at char: "+l);}return k}va();for(var d=0;;){var f=c(-1),e=c(0),g=c(64),h=c(64);if(64===h&&-1===f)break;b(f<<2|e>>4);64!=g&&(b(e<<4&240|g>>2),64!=h&&b(g<<6&192|h))}}
+function va(){if(!u){u={};for(var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""),b=["+/=","+/","-_=","-_.","-_"],c=0;5>c;c++){var d=a.concat(b[c].split(""));ta[c]=d;for(var f=0;f<d.length;f++){var e=d[f];void 0===u[e]&&(u[e]=f)}}}};var ya="undefined"!==typeof Uint8Array;function za(a){return null==a||v(a)?a:"string"===typeof a?wa(a):null}function v(a){return ya&&null!=a&&a instanceof Uint8Array}var w={};var Aa;function Ba(a){if(a!==w)throw Error("illegal external caller");}function x(a,b){Ba(b);this.H=a;if(null!=a&&0===a.length)throw Error("ByteString should be constructed with non-empty values");}function Ca(){return Aa||(Aa=new x(null,w))}function Da(a){var b=a.H;return null==b?"":"string"===typeof b?b:a.H=ua(b)};var y="function"===typeof Symbol&&"symbol"===typeof Symbol()?Symbol():void 0;function z(a,b){if(y)return a[y]|=b;if(void 0!==a.u)return a.u|=b;Object.defineProperties(a,{u:{value:b,configurable:!0,writable:!0,enumerable:!1}});return b}function Ea(a,b){y?a[y]&&(a[y]&=~b):void 0!==a.u&&(a.u&=~b)}function A(a){var b;y?b=a[y]:b=a.u;return null==b?0:b}function B(a,b){y?a[y]=b:void 0!==a.u?a.u=b:Object.defineProperties(a,{u:{value:b,configurable:!0,writable:!0,enumerable:!1}})}
+function C(a){z(a,1);return a}function E(a){return!!(A(a)&2)}function Fa(a){z(a,16);return a}function Ga(a,b){B(b,(a|0)&-51)}function Ha(a,b){B(b,(a|18)&-41)};var F={};function H(a){return null!==a&&"object"===typeof a&&!Array.isArray(a)&&a.constructor===Object}var Ia;function Ja(a){a instanceof x&&(Ba(w),a=a.H||"");return a}var I,Ka=[];B(Ka,23);I=Object.freeze(Ka);function J(a){if(E(a.j))throw Error("Cannot mutate an immutable Message");}function La(a){var b=a.length;(b=b?a[b-1]:void 0)&&H(b)?b.g=1:(b={},a.push((b.g=1,b)))};function Ma(a){return a}function Na(a){return a};function Oa(a,b){a=a||{};b=b||{};var c={},d;for(d in a)c[d]=0;for(var f in b)c[f]=0;for(var e in c)if(!Pa(a[e],b[e]))return!1;return!0}function Qa(a){return a&&"object"===typeof a?a.j||a:a}
+function Pa(a,b){a=Ja(a);b=Ja(b);a=Qa(a);b=Qa(b);if(a==b)return!0;if(ya){var c=v(a),d=v(b);if(c||d){if(!c)if("string"===typeof a)a=za(a);else return!1;if(d)d=b;else if("string"===typeof b)d=za(b);else return!1;if(a.length!==d.length)return!1;for(b=0;b<a.length;b++)if(a[b]!==d[b])return!1;return!0}}if(null==a&&Array.isArray(b)&&A(b)&1&&!b.length||null==b&&Array.isArray(a)&&A(a)&1&&!a.length)return!0;if(!qa(a)||!qa(b))return"number"===typeof a&&isNaN(a)||"number"===typeof b&&isNaN(b)?String(a)==String(b):
+!1;if(a.constructor!=b.constructor)return!1;if(a.constructor===Array){d=a;c=a=void 0;for(var f=Math.max(d.length,b.length),e=0;e<f;e++){var g=d[e],h=b[e];g&&g.constructor==Object&&(a=g,g=void 0);h&&h.constructor==Object&&(c=h,h=void 0);if(!Pa(g,h))return!1}return a||c?(a=a||{},c=c||{},Oa(a,c)):!0}if(a.constructor===Object)return Oa(a,b);throw Error("Invalid type in JSPB array");};var K;function Ra(a){switch(typeof a){case "number":return isFinite(a)?a:String(a);case "object":if(a)if(Array.isArray(a)){if(0!==(A(a)&128))return a=Array.prototype.slice.call(a),La(a),a}else{if(v(a))return ua(a);if(a instanceof x)return Da(a)}}return a};function Sa(a,b,c,d){if(null!=a){if(Array.isArray(a))a=Ta(a,b,c,void 0!==d);else if(H(a)){var f={},e;for(e in a)f[e]=Sa(a[e],b,c,d);a=f}else a=b(a,d);return a}}function Ta(a,b,c,d){var f=A(a);d=d?!!(f&16):void 0;a=Array.prototype.slice.call(a);for(var e=0;e<a.length;e++)a[e]=Sa(a[e],b,c,d);c(f,a);return a}function Ua(a){return a.F===F?a.toJSON():Ra(a)}function Va(a){if(!a)return a;if("object"===typeof a){if(v(a))return new Uint8Array(a);if(a.F===F)return Wa(a)}return a}
+function Xa(a,b){a&128&&La(b)};function Ya(a){return a.h||(a.h=a.j[a.i+a.A]={})}function L(a,b,c){return-1===b?null:b>=a.i?a.h?a.h[b]:void 0:c&&a.h&&(c=a.h[b],null!=c)?c:a.j[b+a.A]}function M(a,b,c,d){a.o&&(a.o=void 0);if(b>=a.i||d)return Ya(a)[b]=c,a;a.j[b+a.A]=c;(c=a.h)&&b in c&&delete c[b];return a}
+function Za(a,b,c,d,f){var e=L(a,b,d);Array.isArray(e)||(e=I);var g=A(e);g&1||C(e);if(f)g&2||z(e,2),c&1||Object.freeze(e);else{f=!(c&2);var h=g&2;c&1||!h?f&&g&16&&!h&&Ea(e,16):(e=C(Array.prototype.slice.call(e)),M(a,b,e,d))}return e}function O(a,b){return Za(a,b,0,!1,E(a.j))}
+function P(a,b,c,d){var f=E(a.j),e=Za(a,b,1,d,f),g=A(e);if(!(g&4)){Object.isFrozen(e)&&(e=C(e.slice()),M(a,b,e,d));for(var h=0,k=0;h<e.length;h++){var l=c(e[h]);null!=l&&(e[k++]=l)}k<h&&(e.length=k);z(e,5);f&&(z(e,2),Object.freeze(e))}!f&&(g&2||Object.isFrozen(e))&&(e=Array.prototype.slice.call(e),z(e,5),c=e,null==c?c=I:(f=A(c),1!==(f&1)&&(Object.isFrozen(c)&&(c=Array.prototype.slice.call(c)),B(c,f|1))),J(a),M(a,b,c,d));return e}
+function $a(a){return null==a?a:"string"===typeof a?a?new x(a,w):Ca():a.constructor===x?a:v(a)?a.length?new x(new Uint8Array(a),w):Ca():void 0}function Q(a,b){a=L(a,b);return null==a?0:a}function R(a,b,c,d){J(a);c!==d?M(a,b,c):M(a,b,void 0,!1);return a}var ab=Symbol(void 0);function bb(a,b,c,d){var f=L(a,c,d);var e=!1;var g=null==f||"object"!==typeof f||(e=Array.isArray(f))||f.F!==F?e?new b(f):void 0:f;g!==f&&null!=g&&(M(a,c,g,d),z(g.j,A(a.j)&-33));return g}
+function S(a,b,c){if(a=bb(a,b,c,!1))b=a;else if(a=b[ab])b=a;else{a=new b;if(ra!==ra)throw Error("requires a valid immutable API token");E(a.j)||((c=a.o)&&Pa(c.j,a.j)?a=c:(c=cb(a,!0),z(c.j,2),a=a.o=c));b=b[ab]=a}return b}function T(a,b,c){var d=void 0===d?!1:d;b=bb(a,b,c,d);if(null==b)return b;if(!E(a.j)){var f=db(b);f!==b&&(b=f,M(a,c,b,d))}return b}
+function eb(a,b,c,d,f,e){a.m||(a.m={});var g=a.m[c],h=Za(a,c,3,d,e);if(g)e||(Object.isFrozen(g)?f||(g=Array.prototype.slice.call(g),a.m[c]=g):f&&Object.freeze(g));else{g=[];var k=!!(A(a.j)&16),l=E(h);!e&&l&&(h=C(Array.prototype.slice.call(h)),M(a,c,h,d));d=l;for(var m=0;m<h.length;m++){var q=h[m];var G=b;var D=k,N=!1;N=void 0===N?!1:N;D=void 0===D?!1:D;G=Array.isArray(q)?new G(D?Fa(q):q):N?new G:void 0;void 0!==G&&(d=d||E(q),g.push(G),l&&z(G.j,2))}a.m[c]=g;a=h;Object.isFrozen(a)||(b=A(a)|33,B(a,d?
+b&-9:b|8));(e||f&&l)&&z(g,2);(e||f)&&Object.freeze(g)}return g}function U(a,b,c,d){var f=E(a.j);b=eb(a,b,c,d,f,f);a=Za(a,c,3,d,f);if(!(f||A(a)&8)){for(f=0;f<b.length;f++)c=b[f],d=db(c),c!==d&&(b[f]=d,a[f]=b[f].j);z(a,8)}return b}function fb(a,b,c){J(a);null==c&&(c=void 0);return M(a,b,c)}function gb(a,b,c,d){J(a);if(null!=c){var f=C([]);for(var e=!1,g=0;g<c.length;g++)f[g]=c[g].j,e=e||E(f[g]);a.m||(a.m={});a.m[b]=c;c=f;e?Ea(c,8):z(c,8)}else a.m&&(a.m[b]=void 0),f=I;M(a,b,f,d)}
+function V(a,b){return null==a?b:a}function W(a,b){a=L(a,b);return V(null==a?a:!!a,!1)};function hb(a){var b=A(a);if(b&2)return a;a=sa(a,ib);Ha(b,a);Object.freeze(a);return a}function jb(a,b,c){c=void 0===c?Ha:c;if(null!=a){if(ya&&a instanceof Uint8Array)return a.length?new x(new Uint8Array(a),w):Ca();if(Array.isArray(a)){var d=A(a);if(d&2)return a;if(b&&!(d&32)&&(d&16||0===d))return B(a,d|2),a;a=Ta(a,jb,c,!0);b=A(a);b&4&&b&2&&Object.freeze(a);return a}return a.F===F?ib(a):a}}function ib(a){if(E(a.j))return a;a=cb(a,!0);z(a.j,2);return a}
+function cb(a,b){var c=a.j,d=Fa([]),f=a.constructor.h;f&&d.push(f);0!==(A(c)&128)&&La(d);b=b||E(a.j)?Ha:Ga;f=a.constructor;K=d;d=new f(d);K=void 0;a.C&&(d.C=a.C.slice());f=!!(A(c)&16);for(var e=0;e<c.length;e++){var g=c[e];if(e===c.length-1&&H(g))for(var h in g){var k=+h;if(Number.isNaN(k))Ya(d)[k]=g[k];else{var l=g[h],m=a.m&&a.m[k];m?gb(d,k,hb(m),!0):(l=jb(l,f,b),J(d),M(d,k,l,!0))}}else k=e-a.A,(l=a.m&&a.m[k])?gb(d,k,hb(l),!1):(g=jb(g,f,b),J(d),M(d,k,g,!1))}return d}
+function db(a){if(!E(a.j))return a;var b=cb(a,!1);b.o=a;return b};function X(a,b,c){null==a&&(a=K);K=void 0;var d=this.constructor.i||0,f=0<d,e=this.constructor.h,g=!1;if(null==a){a=e?[e]:[];var h=!0;B(a,48)}else{if(!Array.isArray(a))throw Error();if(e&&e!==a[0])throw Error();var k=z(a,0),l=k;if(h=0!==(16&l))(g=0!==(32&l))||(l|=32);if(f)if(128&l)d=0;else{if(0<a.length){var m=a[a.length-1];if(H(m)&&"g"in m){d=0;l|=128;delete m.g;var q=!0,G;for(G in m){q=!1;break}q&&a.pop()}}}else if(128&l)throw Error();k!==l&&B(a,l)}this.A=(e?0:-1)-d;this.m=void 0;this.j=a;a:{e=
+this.j.length;d=e-1;if(e&&(e=this.j[d],H(e))){this.h=e;this.i=d-this.A;break a}void 0!==b&&-1<b?(this.i=Math.max(b,d+1-this.A),this.h=void 0):this.i=Number.MAX_VALUE}if(!f&&this.h&&"g"in this.h)throw Error('Unexpected "g" flag in sparse object of message that is not a group type.');if(c){b=h&&!g&&!0;f=this.i;var D;for(h=0;h<c.length;h++)g=c[h],g<f?(g+=this.A,(d=a[g])?kb(d,b):a[g]=I):(D||(D=Ya(this)),(d=D[g])?kb(d,b):D[g]=I)}}X.prototype.toJSON=function(){var a=this.j;return Ia?a:Ta(a,Ua,Xa)};
+function Wa(a){var b=Ta(a.j,Va,Ga);Fa(b);K=b;b=new a.constructor(b);K=void 0;lb(b,a);return b}function kb(a,b){if(Array.isArray(a)){var c=A(a),d=1;!b||c&2||(d|=16);(c&d)!==d&&B(a,c|d)}}X.prototype.F=F;X.prototype.toString=function(){return this.j.toString()};function mb(a,b){return Ra(b)}
+function lb(a,b){b.C&&(a.C=b.C.slice());var c=b.m;if(c){var d=b.h,f;for(f in c)if(b=c[f]){var e=!(!d||!d[f]),g=+f;if(Array.isArray(b)){if(b.length)for(e=U(a,b[0].constructor,g,e),g=0;g<Math.min(e.length,b.length);g++)lb(e[g],b[g])}else throw a=typeof b,Error("unexpected object: type: "+("object"!=a?a:b?Array.isArray(b)?"array":a:"null")+": "+b);}}};var nb=void 0;function ob(a){var b=nb;nb=void 0;if(!Array.isArray(a))throw b=b?b()+"\n":"",Error(b+String(a));return a};function pb(a){return JSON.stringify([a.map(function(b){var c={};return[(c[b.L]=b.message.toJSON(),c)]})])};function qb(a){this.h=a}qb.prototype.K=function(){var a=encodeURIComponent;var b=pb(oa.apply(0,arguments));for(var c=[],d=0,f=0;f<b.length;f++){var e=b.charCodeAt(f);255<e&&(c[d++]=e&255,e>>=8);c[d++]=e}b=ua(c,3);a=a(b);this.h("https://pagead2.googlesyndication.com/pagead/ping?e=3&d="+a)};function rb(a){X.call(this,a)}r(rb,X);function sb(a){X.call(this,a,-1,tb)}r(sb,X);var tb=[3];function ub(a){X.call(this,a,-1,vb)}r(ub,X);var vb=[3];function wb(a){X.call(this,a,-1,xb)}r(wb,X);var xb=[2,3,5];function yb(a){X.call(this,a,-1,zb)}r(yb,X);function Ab(a){X.call(this,a,-1,Bb)}r(Ab,X);function Cb(a){X.call(this,a,-1,Db)}r(Cb,X);var zb=[1,2],Bb=[3,4,9],Db=[3,4,5,6,7];function Y(a){X.call(this,a)}r(Y,X);function Eb(a){X.call(this,a,-1,Fb)}r(Eb,X);var Fb=[1,2,3];function Gb(a){X.call(this,a,-1,Hb)}r(Gb,X);var Hb=[1];function Ib(a){X.call(this,a,-1,Jb)}r(Ib,X);var Jb=[1];function Kb(a){X.call(this,a,-1,Lb)}r(Kb,X);var Lb=[1];function Mb(a){X.call(this,a,-1,Nb)}r(Mb,X);var Nb=[1];function Z(a){X.call(this,a)}r(Z,X);function Ob(a){X.call(this,a,-1,Pb)}r(Ob,X);function Qb(a){X.call(this,a)}r(Qb,X);var Pb=[1];function Rb(a){X.call(this,a)}r(Rb,X);function Sb(a){X.call(this,a)}r(Sb,X);function Tb(a){X.call(this,a)}r(Tb,X);function Ub(a){X.call(this,a)}r(Ub,X);function Vb(a){X.call(this,a,-1,Wb)}r(Vb,X);var Wb=[1];function Xb(a){X.call(this,a,-1,Yb)}r(Xb,X);var Yb=[1,2];function Zb(a){X.call(this,a,-1,$b)}r(Zb,X);var $b=[1];function ac(a){X.call(this,a,-1,bc)}r(ac,X);var bc=[2,3,6,10];function cc(a){X.call(this,a)}r(cc,X);function dc(a,b){return R(a,1,b,"")}function ec(a,b){return fb(a,2,b)};var fc={ja:0,V:1,X:2,ca:3,Z:4,Y:5,aa:6,ba:7,da:8,ea:12,U:9,N:10,W:11};var gc={ka:0,ha:1,S:2,T:3,fa:4,M:5,ia:6,ga:7,P:8,O:9,R:10};function hc(a){X.call(this,a,-1,ic)}r(hc,X);function jc(a,b){fb(a,8,b)}function kc(a){X.call(this,a,-1,lc)}r(kc,X);function mc(a,b){return R(a,2,b,"")}function nc(a,b){return R(a,3,b,"")}var ic=[9],lc=[6];function oc(a){a.K.apply(a,ha(oa.apply(1,arguments).map(function(b){return{L:10,message:b}})))};function pc(a){X.call(this,a,-1,qc)}r(pc,X);var qc=[1];function rc(a,b,c){if(Q(a,2)!==Q(b,2))return c;var d=!1;switch(Q(a,2)){case 1:a:{var f,e=new Set(null!=(f=O(a,3))?f:[]);b=p(O(b,3));for(f=b.next();!f.done;f=b.next())if(e.has(f.value)){d=!0;break a}d=!1}break;case 0:a:{f=new Set(null!=(e=P(a,4,Na,!1))?e:[]);b=p(P(b,4,Na,!1));for(e=b.next();!e.done;e=b.next())if(f.has(e.value)){d=!0;break a}d=!1}break;case 2:b=new sc(b);d=(f=T(a,wb,5))?tc(b,f):!1;break;case 3:a:{f=new Set;e=p(P(a,9,$a));for(d=e.next();!d.done;d=e.next())f.add(Da(d.value));if(0===f.size)d=
+!0;else{b=p(P(b,6,$a));for(e=b.next();!e.done;e=b.next())if(f.has(Da(e.value))){d=!0;break a}d=!1}}break;case 4:d=uc(a,b)}return W(a,6)?d?null:c:d?c:null}
+function uc(a,b){a=T(a,sb,10);if(void 0===a)return!1;var c=U(b,ub,7);if(0===c.length)return!1;b=!0;c=p(c);for(var d=c.next();!d.done;d=c.next())if(d=d.value,V(L(d,1),0)===V(L(a,1),0)&&V(L(d,2),0)===V(L(a,2),0)){b&&(b=!1);var f=O(d,3);if(0===f.length)return!1;d=!0;f=p(f);for(var e=f.next();!e.done;e=f.next()){e=e.value;var g=Math.floor(e/32),h=O(a,3);if(!(g>=h.length||0!==(h[g]>>>e%32)%2)){d=!1;break}}if(d)return!0}return b}
+function tc(a,b){var c=Q(b,1),d=U(b,rb,3),f=U(b,wb,2);switch(c){case 2:c=d.every(function(e){return vc(a,e)})&&f.every(function(e){return tc(a,e)});break;case 1:c=d.some(function(e){return vc(a,e)})||f.some(function(e){return tc(a,e)});break;default:throw Error("unexpected value "+c+"!");}return W(b,4)?!c:c}function sc(a){this.h=new Map;a=p(U(a,rb,5));for(var b=a.next();!b.done;b=a.next()){var c=b.value;b=V(L(c,1),0);c=V(L(c,2),0);var d=this.h.get(b);d||(d=new Set,this.h.set(b,d));d.add(c)}}
+function vc(a,b){var c=V(L(b,2),0);return(a=a.h.get(V(L(b,1),0)))?a.has(c):!1};function wc(a,b){switch(a){case 2:return 187;case 3:return 138;case 4:return xc(b);case 5:return 80;case 6:return 7;case 7:return 2;case 8:return 7;default:return 4}}function xc(a){switch(a){case 2:return 12;case 3:return 14;case 4:return 15;case 5:return 219;case 6:return 82;case 7:return 80;case 8:return 71;case 9:return 16;default:return 4}};function yc(a){return"https://googleads.g.doubleclick.net"===a||"https://td.doubleclick.net"===a};function zc(a,b,c,d,f){this.J=a;this.postRevshareBidCpmUsdMicros=b;this.sellerSignals=c;this.h=d;this.D=f;this.o=new Map;if(W(S(c,Y,12),1)||W(S(c,Y,12),2))a=new hc,this.i=R(a,7,V(L(this.sellerSignals,2),""),"")}zc.prototype.reject=function(a,b){b=void 0===b?0:b;var c,d,f,e,g={ru:null!=(f=null==(c=this.h)?void 0:c.renderUrl)?f:"",igo:null!=(e=null==(d=this.h)?void 0:d.interestGroupOwner)?e:"",s:a,r:b};Ac(this,a,b);return{desirability:0,postRevshareBidCpmUsdMicros:0,debugInfo:this.D?g:void 0,debugEventMessage:this.debugEventMessage}};
+zc.prototype.accept=function(){var a,b,c,d,f={ru:null!=(c=null==(a=this.h)?void 0:a.renderUrl)?c:"",igo:null!=(d=null==(b=this.h)?void 0:b.interestGroupOwner)?d:"",s:1,r:1};Ac(this,1,1);return{desirability:this.postRevshareBidCpmUsdMicros,postRevshareBidCpmUsdMicros:this.postRevshareBidCpmUsdMicros,debugInfo:this.D?f:void 0,debugEventMessage:this.debugEventMessage}};
+function Ac(a,b,c){if(void 0!==a.i){var d=nc(mc(new kc,a.h.interestGroupOwner),a.h.renderUrl);yc(a.h.interestGroupOwner)||R(d,8,a.J,0);fb(a.i,4,d);W(S(a.sellerSignals,Y,12),5)&&(jc(fb(a.i,11,a.sellerSignals),ec(dc(new cc,a.h.renderUrl),a.I)),a.o.forEach(function(h,k){var l;null!=(l=a.i)&&(k=ec(dc(new cc,k),h),J(l),h=eb(l,cc,9,void 0,!1,!1),k=null!=k?k:new cc,l=Za(l,9,2,void 0,!1),h.push(k),l.push(k.j),E(k.j)&&Ea(l,8))}));if(Object.values(gc).includes(b)){var f;null!=(f=a.i)&&R(f,6,b,0)}if(Object.values(fc).includes(c)){var e;
+null!=(e=a.i)&&R(e,5,c,0)}if(1!==b||1!==c){var g;null!=(g=a.i)&&R(g,10,wc(b,c),0)}}}ea.Object.defineProperties(zc.prototype,{debugEventMessage:{configurable:!0,enumerable:!0,get:function(){var a;return null==(a=this.i)?void 0:Wa(a)}}});function Bc(a){var b;this.i=null!=(b=null==a?void 0:V(L(a,4),0))?b:0}Bc.prototype.h=function(a){if(!this.i)return 1;var b;return(null==(b=T(a,Vb,9))?0:O(b,1).includes(this.i))?2:1};function Cc(a,b){return 0===a.size?!1:void 0===b||0===b.length?!0:b.some(function(c){return a.has(c)})}function Dc(a){a=S(S(a,Z,2),Eb,1);this.i=new Set(O(a,1));this.o=W(a,4);this.D=W(a,5)}Dc.prototype.h=function(a){var b;if(Cc(this.i,null==(b=T(a,Xb,1))?void 0:O(b,1)))return 4;a=T(a,Xb,1);return!this.D||a&&!W(a,4)?!this.o||a&&!W(a,3)?1:3:4};function Ec(a){this.i=W(S(S(a,Z,2),Gb,3),2);this.o=new Set(O(S(S(a,Z,2),Gb,3),1))}Ec.prototype.h=function(a){var b=this;return this.i?1:void 0===bb(a,Zb,7,!1)||O(T(a,Zb,7),1).every(function(c){return b.o.has(c)})?1:5};function Fc(a){var b,c,d;this.i=new Set(null!=(d=null==a?void 0:null==(b=T(a,Z,2))?void 0:null==(c=T(b,Ib,4))?void 0:P(c,1,Na,!1))?d:[])}Fc.prototype.h=function(a){var b=this;return 0===this.i.size?1:0===P(a,10,Na,!1).length||P(a,10,Na,!1).some(function(c){return!b.i.has(c)})?6:1};function Gc(a){var b,c;this.i=null!=(c=null==a?void 0:null==(b=T(a,Ob,3))?void 0:U(b,Qb,1))?c:[]}Gc.prototype.h=function(a,b){if(null==b)return 7;if(0===this.i.length)return 1;a=p(this.i);for(var c=a.next();!c.done;c=a.next())if(c=c.value,null!=V(L(c,2),0)&&b<V(L(c,2),0))return 7;return 1};function Hc(a){var b,c,d;this.i=new Set(null!=(d=null==a?void 0:null==(b=T(a,Z,2))?void 0:null==(c=T(b,Kb,2))?void 0:P(c,1,Ma))?d:[])}Hc.prototype.h=function(a){var b=this;return 0!==this.i.size&&P(a,6,Ma).some(function(c){return b.i.has(c)})?8:1};function Ic(a){a=S(S(a,Z,2),Mb,5);this.i=W(a,2);this.o=new Set(O(a,1))}Ic.prototype.h=function(a){var b=this;return this.i?1:O(S(a,Zb,7),1).every(function(c){return b.o.has(c)})?1:9};function Jc(){new pc;return function(a,b,c,d,f){a=new Sb(ob(c.sellerSignals));b=Kc(b,a,d,f,W(a,8)||W(a,22));W(a,8)&&b.debugInfo&&console.log(b.debugInfo);if(W(a,22)&&b.debugInfo){d=b.debugInfo.s;c=b.debugInfo.r;var e,g,h={renderUrl:null!=(e=null==f?void 0:f.renderUrl)?e:"",interestGroupOwner:null!=(g=null==f?void 0:f.interestGroupOwner)?g:"",accepted:!0};if(1!==d||1!==c)h.accepted=!1,h.externalBidStatus=wc(d,c);console.log("Logging debug info of scoreAd().\n",h)}b.debugEventMessage&&(e=b.debugEventMessage,
+g=globalThis.forDebuggingOnly,W(S(a,Y,12),1)&&g.reportAdAuctionWin&&Lc(a,e,g.reportAdAuctionWin,1),W(S(a,Y,12),2)&&g.reportAdAuctionLoss&&Lc(a,e,g.reportAdAuctionLoss,2));return f.topLevelSeller?{desirability:b.desirability,bid:b.postRevshareBidCpmUsdMicros?b.postRevshareBidCpmUsdMicros/1E6:void 0,allowComponentAuction:!0}:{desirability:b.desirability,allowComponentAuction:!0}}}
+function Lc(a,b,c,d){R(b,2,d,0);d=T(b,kc,4);if(W(a,23)&&d&&!yc(V(L(d,2),""))){a=encodeURIComponent;a:{Ia=!0;try{var f=JSON.stringify(b.toJSON(),mb);break a}finally{Ia=!1}f=void 0}c("https://googleads.g.doubleclick.net/td/rdl?tdr="+a(f))}else oc(new qb(c),b)}
+function Mc(a,b){var c,d=null==(c=a.sellerSignals)?void 0:T(c,yb,3),f=null==b?void 0:T(b,yb,11);if(d&&f){c=new Map;for(var e=new Map,g=p(U(d,Ab,1)),h=g.next();!h.done;h=g.next())h=h.value,c.set(Q(h,1),h);d=p(U(d,Cb,2));for(g=d.next();!g.done;g=d.next())g=g.value,e.set(Q(g,1),g);d=new Map;if(g=c&&e&&f)a:{g=p(U(f,Ab,1));for(h=g.next();!h.done;h=g.next()){h=h.value;var k=Q(h,1),l=e.get(k);if(l){var m=null;if(W(h,7)){var q=d.get(k),G=!0,D=V(L(h,8),0);if(void 0===q)q=new Map,d.set(k,q);else{var N=q.get(D);
+if(N){g=N;break a}null===N&&(G=!1)}G&&(m=rc(h,l,k),q.set(D,m))}else m=rc(h,l,k);if(m){g=m;break a}}}f=p(U(f,Cb,2));for(e=f.next();!e.done;e=f.next())if(e=e.value,d=Q(e,1),g=c.get(d))if(e=rc(g,e,d)){g=e;break a}g=null}if(g)return{G:2,B:0}}a:{c=a.postRevshareBidCpmUsdMicros;var da;a=null!=(da=T(a.sellerSignals,Rb,1))?da:new Rb;da=p([new Bc(a),new Dc(a),new Ec(a),new Fc(a),new Gc(a),new Hc(a),new Ic(a)]);for(a=da.next();!a.done;a=da.next())if(a=a.value.h(b,c),1!==a){b=a;break a}b=1}return 1!==b?{G:4,
+B:b}:{G:0,B:1}}
+function Kc(a,b,c,d,f){var e=!!d.componentSeller,g=1E6*a,h=S(S(b,Tb,5),Ub,1);h=L(h,1);h=g*(V(null==h?h:+h,0)||1);a=new zc(a,h,b,d,f);if(d.topLevelSeller&&"https://pubads.g.doubleclick.net"!==d.topLevelSeller)return a.reject(9);var k;f=BigInt((null==(k=T(b,Tb,5))?void 0:V(L(k,2),"0"))||0);if(h<f)return a.reject(5);var l;b=BigInt((null==(l=T(b,Tb,5))?void 0:V(L(l,3),"0"))||0);if(0<b&&g>b)return a.reject(3);if(e)return a.accept();if(!d.renderUrl)return a.reject(7,11);e=null==c?void 0:c.renderUrl;if(null==
+e||!e[d.renderUrl])return a.reject(6,10);var m;e=new ac(ob(null!=(m=null==e?void 0:e[d.renderUrl])?m:[]));a.I=e;m=Mc(a,a.I);if(1!==m.B)return a.reject(m.G,m.B);var q;if(null==(q=d.adComponents)?0:q.length){q=!1;d=p(d.adComponents);for(m=d.next();!m.done;m=d.next())if(m=m.value,l=g=e=void 0,b=null!=(l=null==(e=c)?void 0:null==(g=e.adComponentRenderUrls)?void 0:g[m])?l:[],e=ob(b),e.length&&(q=!0,e=new ac(e),a.o.set(m,e),e=Mc(a,e),1!==e.B))return c=a.reject(e.G,e.B),c.debugInfo&&(c.debugInfo.acru=m),
+c;if(!q)return a.reject(8,12)}return a.accept()};function Nc(a,b,c,d,f){var e=a.metadata.metadata;c={seller:c.seller,decisionLogicUrl:c.decision_logic_uri,trustedScoringSignalsUrl:c.trusted_scoring_signal_uri,interestGroupBuyers:c.custom_audience_buyers,auctionSignals:f,sellerExperimentGroupId:void 0,sellerSignals:d.signals,perBuyerSignals:c.per_buyer_signals};a={topWindowHostname:"",interestGroupOwner:"",renderUrl:a.render_uri,biddingDurationMsec:0};b=Jc()(e,b,c,f,a);return{status:0,score:"number"===typeof b?b:b.desirability}};var Oc=globalThis;Oc.scoreAd=function(a,b,c,d,f){return Nc(a,b,c,d,f)};Oc.scoreAdIterative=function(a,b,c,d){var f=[],e=(new Date).getTime();a=p(a);for(var g=a.next();!g.done;g=a.next())g=g.value,g=Nc(g.ad,g.bid,b,c,d),f.push(g);return{responses:f,status:0,duration:(new Date).getTime()-e}};
diff --git a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
index 33b2bea1da66..0b351013d23a 100644
--- a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
+++ b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
@@ -17,6 +17,7 @@
package android.rubidium.js;
import static com.android.adservices.service.js.JSScriptArgument.arrayArg;
+import static com.android.adservices.service.js.JSScriptArgument.jsonArg;
import static com.android.adservices.service.js.JSScriptArgument.numericArg;
import static com.android.adservices.service.js.JSScriptArgument.recordArg;
import static com.android.adservices.service.js.JSScriptArgument.stringArg;
@@ -26,8 +27,14 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;
+import android.adservices.adselection.AdSelectionConfig;
+import android.adservices.adselection.AdWithBid;
+import android.adservices.common.AdData;
+import android.adservices.common.AdSelectionSignals;
+import android.adservices.common.AdTechIdentifier;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.net.Uri;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.util.Log;
@@ -37,6 +44,12 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.adservices.data.adselection.CustomAudienceSignals;
+import com.android.adservices.service.adselection.AdDataArgument;
+import com.android.adservices.service.adselection.AdSelectionConfigArgument;
+import com.android.adservices.service.adselection.AdWithBidArgument;
+import com.android.adservices.service.adselection.CustomAudienceBiddingSignalsArgument;
+import com.android.adservices.service.adselection.CustomAudienceScoringSignalsArgument;
import com.android.adservices.service.js.IsolateSettings;
import com.android.adservices.service.js.JSScriptArgument;
import com.android.adservices.service.js.JSScriptArrayArgument;
@@ -46,9 +59,11 @@ import com.android.adservices.service.profiling.JSScriptEngineLogConstants;
import com.android.adservices.service.profiling.Profiler;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ListenableFuture;
import org.json.JSONArray;
+import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -58,14 +73,23 @@ import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/** To run the unit tests for this class, run "atest RubidiumPerfTests:JSScriptEnginePerfTests" */
@MediumTest
@@ -78,8 +102,12 @@ public class JSScriptEnginePerfTests {
private static final JSScriptEngine sJSScriptEngine =
JSScriptEngine.getInstanceForTesting(
sContext, Profiler.createInstance(JSScriptEngine.TAG));
-
- @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ private static final Clock CLOCK = Clock.fixed(Instant.now(), ZoneOffset.UTC);
+ private static final Instant ACTIVATION_TIME = CLOCK.instant();
+ private static final Instant EXPIRATION_TIME = CLOCK.instant().plus(Duration.ofDays(1));
+ private static final AdSelectionSignals CONTEXTUAL_SIGNALS = AdSelectionSignals.EMPTY;
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Before
public void before() throws Exception {
@@ -162,6 +190,56 @@ public class JSScriptEnginePerfTests {
runParametrizedTurtledoveScript(75);
}
+ @Test
+ public void evaluate_rubidiumGenerateBid_parametrized_1Ad() throws Exception {
+ runParameterizedRubidiumGenerateBid(1);
+ }
+
+ @Test
+ public void evaluate_rubidiumGenerateBid_parametrized_10Ads() throws Exception {
+ runParameterizedRubidiumGenerateBid(10);
+ }
+
+ @Test
+ public void evaluate_rubidiumGenerateBid_parametrized_25Ads() throws Exception {
+ runParameterizedRubidiumGenerateBid(25);
+ }
+
+ @Test
+ public void evaluate_rubidiumGenerateBid_parametrized_50Ads() throws Exception {
+ runParameterizedRubidiumGenerateBid(50);
+ }
+
+ @Test
+ public void evaluate_rubidiumGenerateBid_parametrized_75Ads() throws Exception {
+ runParameterizedRubidiumGenerateBid(75);
+ }
+
+ @Test
+ public void evaluate_rubidiumScoreAd_parametrized_1Ad() throws Exception {
+ runParameterizedRubidiumScoreAd(1);
+ }
+
+ @Test
+ public void evaluate_rubidiumScoreAd_parametrized_10Ads() throws Exception {
+ runParameterizedRubidiumScoreAd(10);
+ }
+
+ @Test
+ public void evaluate_rubidiumScoreAd_parametrized_25Ads() throws Exception {
+ runParameterizedRubidiumScoreAd(25);
+ }
+
+ @Test
+ public void evaluate_rubidiumScoreAd_parametrized_50Ads() throws Exception {
+ runParameterizedRubidiumScoreAd(50);
+ }
+
+ @Test
+ public void evaluate_rubidiumScoreAd_parametrized_75Ads() throws Exception {
+ runParameterizedRubidiumScoreAd(75);
+ }
+
@SuppressLint("DefaultLocale")
private void runParametrizedTurtledoveScript(int numAds) throws Exception {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -190,7 +268,7 @@ public class JSScriptEnginePerfTests {
"(%s: %d)",
JSScriptEngineLogConstants.WEBVIEW_EXECUTION_TIME, webviewExecTime);
// The listener picks up logs from JSScriptEngine, so simulate logging from there.
- Log.d("JSScriptEngine", webviewExecTimeLog);
+ Log.d(TAG, webviewExecTimeLog);
}
}
@@ -202,7 +280,9 @@ public class JSScriptEnginePerfTests {
ImmutableList.of(
stringArg(
"renderUrl",
- "https://googleads.g.doubleclick.net/ads/simple-ad.html?adg_id=52836427830&cr_id=310927197297&cv_id=4"),
+ "https://googleads.g.doubleclick.net/ads/simple-ad"
+ + ".html?adg_id=52836427830&cr_id=310927197297"
+ + "&cv_id=4"),
stringArrayArg(
"metadata",
ImmutableList.of(
@@ -350,4 +430,171 @@ public class JSScriptEnginePerfTests {
private String readAsset(@NonNull String assetName) throws IOException {
return new String(readBinaryAsset(assetName), StandardCharsets.UTF_8);
}
+
+ public void runParameterizedRubidiumGenerateBid(int numOfAds) throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.pauseTiming();
+ List<AdData> adDataList = getSampleAdDataList(numOfAds, "https://ads.example/");
+ ImmutableList.Builder<JSScriptArgument> adDataListArgument = new ImmutableList.Builder<>();
+ for (AdData adData : adDataList) {
+ adDataListArgument.add(AdDataArgument.asScriptArgument("ignored", adData));
+ }
+ AdSelectionSignals perBuyerSignals = generatePerBuyerSignals(numOfAds);
+ AdSelectionSignals auctionSignals = AdSelectionSignals.fromString("{\"auctionSignal1"
+ + "\":\"auctionValue1\",\"auctionSignal2\":\"auctionValue2\"}");
+
+ AdTechIdentifier buyer = AdTechIdentifier.fromString("https://example-dsp.com");
+ AdSelectionSignals trustedBiddingSignals = AdSelectionSignals.fromString("{\"key1"
+ + "\":\"tbs1\",\"key2\":{}}");
+ CustomAudienceSignals customAudienceSignals = getSampleCustomAudienceSignals(buyer,
+ "shoes-running");
+
+ ImmutableList<JSScriptArgument> args = ImmutableList.<JSScriptArgument>builder()
+ .add(arrayArg("ads", adDataListArgument.build()))
+ .add(jsonArg("auctionSignals", auctionSignals))
+ .add(jsonArg("perBuyerSignals", perBuyerSignals))
+ .add(jsonArg("trustedBiddingSignals", trustedBiddingSignals))
+ .add(jsonArg("contextualSignals", CONTEXTUAL_SIGNALS))
+ .add(CustomAudienceBiddingSignalsArgument.asScriptArgument(
+ "customAudienceBiddingSignal", customAudienceSignals))
+ .build();
+ InputStream testJsInputStream = sContext.getAssets().open(
+ "rubidium_bidding_logic_compiled.js");
+ String jsTestFile = new String(testJsInputStream.readAllBytes(), StandardCharsets.UTF_8);
+ //logging time taken to call JS
+ state.resumeTiming();
+ while (state.keepRunning()) {
+ String res = callJSEngine(jsTestFile, args, "generateBidIterative");
+ JSONObject jsonObject = new JSONObject(res);
+ long webviewExecTime = jsonObject.getLong("duration");
+ String webviewExecTimeLog =
+ String.format(Locale.ENGLISH,
+ "(%s: %d)",
+ JSScriptEngineLogConstants.WEBVIEW_EXECUTION_TIME,
+ webviewExecTime);
+ // The listener picks up logs from JSScriptEngine, so simulate logging from there.
+ Log.d(TAG, webviewExecTimeLog);
+ }
+ }
+
+ public void runParameterizedRubidiumScoreAd(int numOfAds) throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.pauseTiming();
+ String adRenderUrl = "https://rtb.example/creative";
+ List<AdWithBid> adWithBidList = getSampleAdDataWithBidList(numOfAds, adRenderUrl);
+ ImmutableList.Builder<JSScriptArgument> adWithBidArrayArgument =
+ new ImmutableList.Builder<>();
+ for (AdWithBid adWithBid : adWithBidList) {
+ adWithBidArrayArgument.add(AdWithBidArgument.asScriptArgument("adWithBid", adWithBid));
+ }
+ AdTechIdentifier seller = AdTechIdentifier.fromString("www.example-ssp.com");
+ AdSelectionSignals sellerSignals = AdSelectionSignals.fromString("{\"signals\":[]}");
+ String trustedScoringSignalJson = String.format(Locale.ENGLISH,
+ "{\"renderUrl\":{\"%s\":[]}}", adRenderUrl);
+ AdSelectionSignals trustedScoringSignalsJson = AdSelectionSignals.fromString(
+ trustedScoringSignalJson);
+
+ AdTechIdentifier buyer1 = AdTechIdentifier.fromString("https://example-dsp.com");
+ AdSelectionSignals buyer1Signals = AdSelectionSignals.fromString("{\"https://example-dsp"
+ + ".com:1\":\"value1\",\"https://example-dsp.com:2\":\"value2\"}");
+ Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals = ImmutableMap.of(buyer1,
+ buyer1Signals);
+
+ AdSelectionConfig adSelectionConfig = getSampleAdSelectionConfig(seller, sellerSignals,
+ perBuyerSignals);
+ CustomAudienceSignals customAudienceSignals = getSampleCustomAudienceSignals(buyer1,
+ "shoes-running");
+
+ ImmutableList<JSScriptArgument> args = ImmutableList.<JSScriptArgument>builder()
+ .add(arrayArg("adsWithBids", adWithBidArrayArgument.build()))
+ .add(AdSelectionConfigArgument.asScriptArgument(adSelectionConfig,
+ "adSelectionConfig"))
+ .add(jsonArg("sellerSignals", sellerSignals))
+ .add(jsonArg("trustedScoringSignals", trustedScoringSignalsJson))
+ .add(jsonArg("contextualSignals", CONTEXTUAL_SIGNALS))
+ .add(CustomAudienceScoringSignalsArgument.asScriptArgument(
+ "customAudienceScoringSignal", customAudienceSignals))
+ .build();
+ InputStream testJsInputStream = sContext.getAssets().open(
+ "rubidium_scoring_logic_compiled.js");
+ String jsTestFile = new String(testJsInputStream.readAllBytes(), StandardCharsets.UTF_8);
+ //logging time taken to call JS
+ state.resumeTiming();
+ while (state.keepRunning()) {
+ String res = callJSEngine(jsTestFile, args, "scoreAdIterative");
+ JSONObject jsonObject = new JSONObject(res);
+ long webviewExecTime = jsonObject.getLong("duration");
+ String webviewExecTimeLog =
+ String.format(Locale.ENGLISH,
+ "(%s: %d)",
+ JSScriptEngineLogConstants.WEBVIEW_EXECUTION_TIME,
+ webviewExecTime);
+ // The listener picks up logs from JSScriptEngine, so simulate logging from there.
+ Log.d(TAG, webviewExecTimeLog);
+ }
+ }
+
+ private List<AdWithBid> getSampleAdDataWithBidList(int size, String baseUri) {
+ double initialBid = 1.23;
+ return IntStream.rangeClosed(1, size).mapToObj(iterator -> {
+ Uri renderUri = Uri.parse(String.format(Locale.ENGLISH, "%s%d", baseUri, iterator));
+ String metaDataJson = String.format(Locale.ENGLISH, "{\"metadata\":[\"%d\",\"123\"]}",
+ iterator);
+ AdData adData = new AdData.Builder().setRenderUri(renderUri).setMetadata(
+ metaDataJson).build();
+ return new AdWithBid(adData, initialBid + iterator);
+ }).collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ private List<AdData> getSampleAdDataList(int size, String baseUri) {
+ return IntStream.rangeClosed(1, size).mapToObj(iterator -> {
+ Uri renderUri = Uri.parse(String.format(Locale.ENGLISH, "%s%d", baseUri, iterator));
+ String metaDataJson = String.format(Locale.ENGLISH, "{\"metadata\":[\"%d\",\"123\"]}",
+ iterator);
+ return new AdData.Builder().setRenderUri(renderUri).setMetadata(
+ metaDataJson).build();
+ }).collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ private CustomAudienceSignals getSampleCustomAudienceSignals(AdTechIdentifier buyer,
+ String name) {
+ String owner = "www.example-dsp.com";
+ AdSelectionSignals userBiddingSignals = AdSelectionSignals.fromString("{\"signals\":[]}");
+ return new CustomAudienceSignals.Builder()
+ .setOwner(owner)
+ .setBuyer(buyer)
+ .setActivationTime(ACTIVATION_TIME)
+ .setExpirationTime(EXPIRATION_TIME)
+ .setUserBiddingSignals(userBiddingSignals)
+ .setName(name)
+ .build();
+ }
+
+ private AdSelectionConfig getSampleAdSelectionConfig(AdTechIdentifier seller,
+ AdSelectionSignals sellerSignals,
+ Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals) {
+ Uri decisionLogicUri = Uri.parse("https://www.example-ssp.com/decide.js");
+ Uri trustedScoringSignalsUri = Uri.parse("https://www.example-ssp.com/signals");
+ List<AdTechIdentifier> buyers = ImmutableList.copyOf(
+ new ArrayList<>(perBuyerSignals.keySet()));
+ return new AdSelectionConfig.Builder()
+ .setSeller(seller)
+ .setDecisionLogicUri(decisionLogicUri)
+ .setCustomAudienceBuyers(buyers)
+ .setAdSelectionSignals(AdSelectionSignals.EMPTY)
+ .setSellerSignals(sellerSignals)
+ .setPerBuyerSignals(perBuyerSignals)
+ .setTrustedScoringSignalsUri(trustedScoringSignalsUri)
+ .build();
+ }
+
+ private AdSelectionSignals generatePerBuyerSignals(int size) {
+ String signalArrayFormat = "[\"%d\",\"123\",%d]";
+ String signalArray = IntStream.rangeClosed(1, size)
+ .mapToObj(i -> String.format(Locale.ENGLISH, signalArrayFormat, i, i))
+ .collect(Collectors.joining(", ", "[", "]"));
+ return AdSelectionSignals.fromString(
+ String.format(Locale.ENGLISH, "{\"signals\":[null,%s,[null]]}",
+ signalArray));
+ }
}
diff --git a/apct-tests/perftests/settingsprovider/Android.bp b/apct-tests/perftests/settingsprovider/Android.bp
new file mode 100644
index 000000000000..43ec0e0b4620
--- /dev/null
+++ b/apct-tests/perftests/settingsprovider/Android.bp
@@ -0,0 +1,39 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "SettingsProviderPerfTests",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "platform-compat-test-rules",
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ "collector-device-lib-platform",
+ "cts-install-lib-java",
+ "services.core",
+ ],
+
+ libs: ["android.test.base"],
+
+ platform_apis: true,
+
+ test_suites: ["device-tests"],
+
+ data: [":perfetto_artifacts"],
+
+ certificate: "platform",
+}
diff --git a/apct-tests/perftests/settingsprovider/AndroidManifest.xml b/apct-tests/perftests/settingsprovider/AndroidManifest.xml
new file mode 100644
index 000000000000..140c280115b6
--- /dev/null
+++ b/apct-tests/perftests/settingsprovider/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.perftests.multiuser">
+
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.multiuser"/>
+
+</manifest>
diff --git a/apct-tests/perftests/settingsprovider/OWNERS b/apct-tests/perftests/settingsprovider/OWNERS
new file mode 100644
index 000000000000..86ae5818e91c
--- /dev/null
+++ b/apct-tests/perftests/settingsprovider/OWNERS
@@ -0,0 +1 @@
+include /PACKAGE_MANAGER_OWNERS
diff --git a/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java b/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java
new file mode 100644
index 000000000000..e31162f37cf8
--- /dev/null
+++ b/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.provider;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public final class SettingsProviderPerfTest {
+ private static final String NAMESPACE = "test@namespace";
+ private static final String SETTING_NAME1 = "test:setting1";
+ private static final String SETTING_NAME2 = "test-setting2";
+
+ private final ContentResolver mContentResolver;
+
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public SettingsProviderPerfTest() {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ mContentResolver = context.getContentResolver();
+ }
+
+ @Before
+ public void setUp() {
+ Settings.Secure.putString(mContentResolver, SETTING_NAME1, "1");
+ Settings.Config.putString(NAMESPACE, SETTING_NAME1, "1", true);
+ Settings.Config.putString(NAMESPACE, SETTING_NAME2, "2", true);
+ }
+
+ @After
+ public void destroy() {
+ Settings.Secure.putString(mContentResolver, SETTING_NAME1, "null");
+ Settings.Config.deleteString(NAMESPACE, SETTING_NAME1);
+ Settings.Config.deleteString(NAMESPACE, SETTING_NAME2);
+ }
+
+ @Test
+ public void testSettingsValueConsecutiveRead() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Writing to setting2 should not invalidate setting1's cache
+ Settings.Secure.putString(mContentResolver, SETTING_NAME2, Integer.toString(i));
+ i++;
+ state.resumeTiming();
+ Settings.Secure.getString(mContentResolver, SETTING_NAME1);
+ }
+ }
+
+ @Test
+ public void testSettingsValueConsecutiveReadAfterWrite() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Triggering the invalidation of setting1's cache
+ Settings.Secure.putString(mContentResolver, SETTING_NAME1, Integer.toString(i));
+ i++;
+ state.resumeTiming();
+ Settings.Secure.getString(mContentResolver, SETTING_NAME1);
+ }
+ }
+
+ @Test
+ public void testSettingsNamespaceConsecutiveRead() {
+ final List<String> names = new ArrayList<>();
+ names.add(SETTING_NAME1);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Settings.Config.getStrings(mContentResolver, NAMESPACE, names);
+ }
+ }
+
+ @Test
+ public void testSettingsNamespaceConsecutiveReadAfterWrite() {
+ final List<String> names = new ArrayList<>();
+ names.add(SETTING_NAME1);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Triggering the invalidation of the list's cache
+ Settings.Config.putString(NAMESPACE, SETTING_NAME2, Integer.toString(i), true);
+ i++;
+ state.resumeTiming();
+ Settings.Config.getStrings(mContentResolver, NAMESPACE, names);
+ }
+ }
+}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index e88e979460b8..62799598cf6a 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -416,6 +416,11 @@ public abstract class JobService extends Service {
* JobScheduler will not remember this notification after the job has finished running,
* so apps must call this every time the job is started (if required or desired).
*
+ * <p>
+ * If separate jobs use the same notification ID with this API, the most recently provided
+ * notification will be shown to the user, and the
+ * {@code jobEndNotificationPolicy} of the last job to stop will be applied.
+ *
* @param params The parameters identifying this job, as supplied to
* the job in the {@link #onStartJob(JobParameters)} callback.
* @param notificationId The ID for this notification, as per
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 16201b29571e..30986dde6b91 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -193,6 +193,7 @@ class JobConcurrencyManager {
}
private final Object mLock;
+ private final JobNotificationCoordinator mNotificationCoordinator;
private final JobSchedulerService mService;
private final Context mContext;
private final Handler mHandler;
@@ -418,6 +419,7 @@ class JobConcurrencyManager {
mLock = mService.getLock();
mContext = service.getTestableContext();
mInjector = injector;
+ mNotificationCoordinator = new JobNotificationCoordinator();
mHandler = JobSchedulerBackgroundThread.getHandler();
@@ -451,7 +453,8 @@ class JobConcurrencyManager {
ServiceManager.getService(BatteryStats.SERVICE_NAME));
for (int i = 0; i < STANDARD_CONCURRENCY_LIMIT; i++) {
mIdleContexts.add(
- mInjector.createJobServiceContext(mService, this, batteryStats,
+ mInjector.createJobServiceContext(mService, this,
+ mNotificationCoordinator, batteryStats,
mService.mJobPackageTracker, mContext.getMainLooper()));
}
}
@@ -1687,7 +1690,7 @@ class JobConcurrencyManager {
@NonNull
private JobServiceContext createNewJobServiceContext() {
- return mInjector.createJobServiceContext(mService, this,
+ return mInjector.createJobServiceContext(mService, this, mNotificationCoordinator,
IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME)),
mService.mJobPackageTracker, mContext.getMainLooper());
@@ -2612,10 +2615,11 @@ class JobConcurrencyManager {
static class Injector {
@NonNull
JobServiceContext createJobServiceContext(JobSchedulerService service,
- JobConcurrencyManager concurrencyManager, IBatteryStats batteryStats,
+ JobConcurrencyManager concurrencyManager,
+ JobNotificationCoordinator notificationCoordinator, IBatteryStats batteryStats,
JobPackageTracker tracker, Looper looper) {
- return new JobServiceContext(service, concurrencyManager, batteryStats,
- tracker, looper);
+ return new JobServiceContext(service, concurrencyManager, notificationCoordinator,
+ batteryStats, tracker, looper);
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
new file mode 100644
index 000000000000..ce5ade5531ec
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.job;
+
+import static android.app.job.JobService.JOB_END_NOTIFICATION_POLICY_DETACH;
+import static android.app.job.JobService.JOB_END_NOTIFICATION_POLICY_REMOVE;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.job.JobService;
+import android.content.pm.UserPackage;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseSetArray;
+
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
+
+class JobNotificationCoordinator {
+ private static final String TAG = "JobNotificationCoordinator";
+
+ /**
+ * Mapping of UserPackage -> {notificationId -> List<JobServiceContext>} to track which jobs
+ * are associated with each app's notifications.
+ */
+ private final ArrayMap<UserPackage, SparseSetArray<JobServiceContext>> mCurrentAssociations =
+ new ArrayMap<>();
+ /**
+ * Set of NotificationDetails for each running job.
+ */
+ private final ArrayMap<JobServiceContext, NotificationDetails> mNotificationDetails =
+ new ArrayMap<>();
+
+ private static final class NotificationDetails {
+ @NonNull
+ public final UserPackage userPackage;
+ public final int notificationId;
+ public final int appPid;
+ public final int appUid;
+ @JobService.JobEndNotificationPolicy
+ public final int jobEndNotificationPolicy;
+
+ NotificationDetails(@NonNull UserPackage userPackage, int appPid, int appUid,
+ int notificationId,
+ @JobService.JobEndNotificationPolicy int jobEndNotificationPolicy) {
+ this.userPackage = userPackage;
+ this.notificationId = notificationId;
+ this.appPid = appPid;
+ this.appUid = appUid;
+ this.jobEndNotificationPolicy = jobEndNotificationPolicy;
+ }
+ }
+
+ private final NotificationManagerInternal mNotificationManagerInternal;
+
+ JobNotificationCoordinator() {
+ mNotificationManagerInternal = LocalServices.getService(NotificationManagerInternal.class);
+ }
+
+ void enqueueNotification(@NonNull JobServiceContext hostingContext, @NonNull String packageName,
+ int callingPid, int callingUid, int notificationId, @NonNull Notification notification,
+ @JobService.JobEndNotificationPolicy int jobEndNotificationPolicy) {
+ validateNotification(packageName, callingUid, notification, jobEndNotificationPolicy);
+ final NotificationDetails oldDetails = mNotificationDetails.get(hostingContext);
+ if (oldDetails != null && oldDetails.notificationId != notificationId) {
+ // App is switching notification IDs. Remove association with the old one.
+ removeNotificationAssociation(hostingContext);
+ }
+ final int userId = UserHandle.getUserId(callingUid);
+ // TODO(260848384): ensure apps can't cancel the notification for user-initiated job
+ // eg., by calling NotificationManager.cancel/All or deleting the notification channel
+ mNotificationManagerInternal.enqueueNotification(
+ packageName, packageName, callingUid, callingPid, /* tag */ null,
+ notificationId, notification, userId);
+ final UserPackage userPackage = UserPackage.of(userId, packageName);
+ final NotificationDetails details = new NotificationDetails(
+ userPackage, callingPid, callingUid, notificationId, jobEndNotificationPolicy);
+ SparseSetArray<JobServiceContext> appNotifications = mCurrentAssociations.get(userPackage);
+ if (appNotifications == null) {
+ appNotifications = new SparseSetArray<>();
+ mCurrentAssociations.put(userPackage, appNotifications);
+ }
+ appNotifications.add(notificationId, hostingContext);
+ mNotificationDetails.put(hostingContext, details);
+ }
+
+ void removeNotificationAssociation(@NonNull JobServiceContext hostingContext) {
+ final NotificationDetails details = mNotificationDetails.remove(hostingContext);
+ if (details == null) {
+ return;
+ }
+ final SparseSetArray<JobServiceContext> associations =
+ mCurrentAssociations.get(details.userPackage);
+ if (associations == null || !associations.remove(details.notificationId, hostingContext)) {
+ Slog.wtf(TAG, "Association data structures not in sync");
+ return;
+ }
+ ArraySet<JobServiceContext> associatedContexts = associations.get(details.notificationId);
+ if (associatedContexts == null || associatedContexts.isEmpty()) {
+ // No more jobs using this notification. Apply the final job stop policy.
+ if (details.jobEndNotificationPolicy == JOB_END_NOTIFICATION_POLICY_REMOVE) {
+ final String packageName = details.userPackage.packageName;
+ mNotificationManagerInternal.cancelNotification(
+ packageName, packageName, details.appUid, details.appPid, /* tag */ null,
+ details.notificationId, UserHandle.getUserId(details.appUid));
+ }
+ }
+ }
+
+ private void validateNotification(@NonNull String packageName, int callingUid,
+ @NonNull Notification notification,
+ @JobService.JobEndNotificationPolicy int jobEndNotificationPolicy) {
+ if (notification == null) {
+ throw new NullPointerException("notification");
+ }
+ if (notification.getSmallIcon() == null) {
+ throw new IllegalArgumentException("small icon required");
+ }
+ if (null == mNotificationManagerInternal.getNotificationChannel(
+ packageName, callingUid, notification.getChannelId())) {
+ throw new IllegalArgumentException("invalid notification channel");
+ }
+ if (jobEndNotificationPolicy != JOB_END_NOTIFICATION_POLICY_DETACH
+ && jobEndNotificationPolicy != JOB_END_NOTIFICATION_POLICY_REMOVE) {
+ throw new IllegalArgumentException("invalid job end notification policy");
+ }
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 6f58c7ce626c..535f8d4cad45 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3212,14 +3212,23 @@ public class JobSchedulerService extends com.android.server.SystemService
/** Returns the maximum amount of time this job could run for. */
public long getMaxJobExecutionTimeMs(JobStatus job) {
synchronized (mLock) {
- final boolean shouldTreatAsDataTransfer = job.getJob().isDataTransfer()
- && checkRunLongJobsPermission(job.getSourceUid(), job.getSourcePackageName());
+ final boolean allowLongerJob;
+ final boolean isDataTransfer = job.getJob().isDataTransfer();
+ if (isDataTransfer || job.shouldTreatAsUserInitiated()) {
+ allowLongerJob =
+ checkRunLongJobsPermission(job.getSourceUid(), job.getSourcePackageName());
+ } else {
+ allowLongerJob = false;
+ }
if (job.shouldTreatAsUserInitiated()) {
- if (shouldTreatAsDataTransfer) {
+ if (isDataTransfer && allowLongerJob) {
return mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS;
}
- return mConstants.RUNTIME_USER_INITIATED_LIMIT_MS;
- } else if (shouldTreatAsDataTransfer) {
+ if (allowLongerJob) {
+ return mConstants.RUNTIME_USER_INITIATED_LIMIT_MS;
+ }
+ return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
+ } else if (isDataTransfer && allowLongerJob) {
return mConstants.RUNTIME_DATA_TRANSFER_LIMIT_MS;
}
return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
@@ -4171,6 +4180,16 @@ public class JobSchedulerService extends com.android.server.SystemService
return mConnectivityController;
}
+ @VisibleForTesting
+ protected QuotaController getQuotaController() {
+ return mQuotaController;
+ }
+
+ @VisibleForTesting
+ protected TareController getTareController() {
+ return mTareController;
+ }
+
// Shell command infrastructure
int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) {
try {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index fead68e021db..df47f1787fdc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -17,8 +17,6 @@
package com.android.server.job;
import static android.app.job.JobInfo.getPriorityString;
-import static android.app.job.JobService.JOB_END_NOTIFICATION_POLICY_DETACH;
-import static android.app.job.JobService.JOB_END_NOTIFICATION_POLICY_REMOVE;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
@@ -61,7 +59,6 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
-import com.android.server.notification.NotificationManagerInternal;
import com.android.server.tare.EconomicPolicy;
import com.android.server.tare.EconomyManagerInternal;
import com.android.server.tare.JobSchedulerEconomicPolicy;
@@ -113,6 +110,7 @@ public final class JobServiceContext implements ServiceConnection {
/** Make callbacks to {@link JobSchedulerService} to inform on job completion status. */
private final JobCompletedListener mCompletedListener;
private final JobConcurrencyManager mJobConcurrencyManager;
+ private final JobNotificationCoordinator mNotificationCoordinator;
private final JobSchedulerService mService;
/** Used for service binding, etc. */
private final Context mContext;
@@ -121,7 +119,6 @@ public final class JobServiceContext implements ServiceConnection {
private final EconomyManagerInternal mEconomyManagerInternal;
private final JobPackageTracker mJobPackageTracker;
private final PowerManager mPowerManager;
- private final NotificationManagerInternal mNotificationManagerInternal;
private PowerManager.WakeLock mWakeLock;
// Execution state.
@@ -174,11 +171,6 @@ public final class JobServiceContext implements ServiceConnection {
/** The absolute maximum amount of time the job can run */
private long mMaxExecutionTimeMillis;
- private int mNotificationId;
- private Notification mNotification;
- private int mNotificationPid;
- private int mNotificationJobStopPolicy;
-
/**
* The stop reason for a pending cancel. If there's not pending cancel, then the value should be
* {@link JobParameters#STOP_REASON_UNDEFINED}.
@@ -254,16 +246,17 @@ public final class JobServiceContext implements ServiceConnection {
}
JobServiceContext(JobSchedulerService service, JobConcurrencyManager concurrencyManager,
+ JobNotificationCoordinator notificationCoordinator,
IBatteryStats batteryStats, JobPackageTracker tracker, Looper looper) {
mContext = service.getContext();
mLock = service.getLock();
mService = service;
mBatteryStats = batteryStats;
mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
- mNotificationManagerInternal = LocalServices.getService(NotificationManagerInternal.class);
mJobPackageTracker = tracker;
mCallbackHandler = new JobServiceHandler(looper);
mJobConcurrencyManager = concurrencyManager;
+ mNotificationCoordinator = notificationCoordinator;
mCompletedListener = service;
mPowerManager = mContext.getSystemService(PowerManager.class);
mAvailable = true;
@@ -624,29 +617,10 @@ public final class JobServiceContext implements ServiceConnection {
Slog.wtfStack(TAG, "Calling UID isn't the same as running job's UID...");
throw new SecurityException("Can't post notification on behalf of another app");
}
- if (notification == null) {
- throw new NullPointerException("notification");
- }
- if (notification.getSmallIcon() == null) {
- throw new IllegalArgumentException("small icon required");
- }
final String callingPkgName = mRunningJob.getServiceComponent().getPackageName();
- if (null == mNotificationManagerInternal.getNotificationChannel(
- callingPkgName, callingUid, notification.getChannelId())) {
- throw new IllegalArgumentException("invalid notification channel");
- }
- if (jobEndNotificationPolicy != JOB_END_NOTIFICATION_POLICY_DETACH
- && jobEndNotificationPolicy != JOB_END_NOTIFICATION_POLICY_REMOVE) {
- throw new IllegalArgumentException("invalid job end notification policy");
- }
- // TODO(260848384): ensure apps can't cancel the notification for user-initiated job
- mNotificationManagerInternal.enqueueNotification(
- callingPkgName, callingPkgName, callingUid, callingPid, /* tag */ null,
- notificationId, notification, UserHandle.getUserId(callingUid));
- mNotificationId = notificationId;
- mNotification = notification;
- mNotificationPid = callingPid;
- mNotificationJobStopPolicy = jobEndNotificationPolicy;
+ mNotificationCoordinator.enqueueNotification(this, callingPkgName,
+ callingPid, callingUid, notificationId,
+ notification, jobEndNotificationPolicy);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1179,13 +1153,7 @@ public final class JobServiceContext implements ServiceConnection {
JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT,
String.valueOf(mRunningJob.getJobId()));
}
- if (mNotification != null
- && mNotificationJobStopPolicy == JOB_END_NOTIFICATION_POLICY_REMOVE) {
- final String callingPkgName = completedJob.getServiceComponent().getPackageName();
- mNotificationManagerInternal.cancelNotification(
- callingPkgName, callingPkgName, completedJob.getUid(), mNotificationPid,
- /* tag */ null, mNotificationId, UserHandle.getUserId(completedJob.getUid()));
- }
+ mNotificationCoordinator.removeNotificationAssociation(this);
if (mWakeLock != null) {
mWakeLock.release();
}
@@ -1203,7 +1171,6 @@ public final class JobServiceContext implements ServiceConnection {
mPendingStopReason = JobParameters.STOP_REASON_UNDEFINED;
mPendingInternalStopReason = 0;
mPendingDebugStopReason = null;
- mNotification = null;
removeOpTimeOutLocked();
if (completedJob.isUserVisibleJob()) {
mService.informObserversOfUserVisibleJobChange(this, completedJob, false);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index d8206ad028a9..404186d27923 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -641,6 +641,9 @@ public final class QuotaController extends StateController {
mTopStartedJobs.add(jobStatus);
// Top jobs won't count towards quota so there's no need to involve the Timer.
return;
+ } else if (jobStatus.shouldTreatAsUserInitiated()) {
+ // User-initiated jobs won't count towards quota.
+ return;
}
final int userId = jobStatus.getSourceUserId();
@@ -892,7 +895,8 @@ public final class QuotaController extends StateController {
// 1. it was started while the app was in the TOP state
// 2. the app is currently in the foreground
// 3. the app overall is within its quota
- return isTopStartedJobLocked(jobStatus)
+ return jobStatus.shouldTreatAsUserInitiated()
+ || isTopStartedJobLocked(jobStatus)
|| isUidInForeground(jobStatus.getSourceUid())
|| isWithinQuotaLocked(
jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
@@ -2116,6 +2120,13 @@ public final class QuotaController extends StateController {
}
void startTrackingJobLocked(@NonNull JobStatus jobStatus) {
+ if (jobStatus.shouldTreatAsUserInitiated()) {
+ if (DEBUG) {
+ Slog.v(TAG, "Timer ignoring " + jobStatus.toShortString()
+ + " because it's user-initiated");
+ }
+ return;
+ }
if (isTopStartedJobLocked(jobStatus)) {
// We intentionally don't pay attention to fg state changes after a TOP job has
// started.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
index cafb02dd7531..de065b2ffa26 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
@@ -313,6 +313,11 @@ public class TareController extends StateController {
@GuardedBy("mLock")
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (jobStatus.shouldTreatAsUserInitiated()) {
+ // User-initiated jobs should always be allowed to run.
+ jobStatus.setTareWealthConstraintSatisfied(nowElapsed, true);
+ return;
+ }
jobStatus.setTareWealthConstraintSatisfied(nowElapsed, hasEnoughWealthLocked(jobStatus));
setExpeditedTareApproved(jobStatus, nowElapsed,
jobStatus.isRequestedExpeditedJob() && canAffordExpeditedBillLocked(jobStatus));
@@ -326,6 +331,11 @@ public class TareController extends StateController {
@Override
@GuardedBy("mLock")
public void prepareForExecutionLocked(JobStatus jobStatus) {
+ if (jobStatus.shouldTreatAsUserInitiated()) {
+ // TODO(202954395): consider noting execution with the EconomyManager even though it
+ // won't affect this job
+ return;
+ }
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
@@ -355,6 +365,9 @@ public class TareController extends StateController {
@Override
@GuardedBy("mLock")
public void unprepareFromExecutionLocked(JobStatus jobStatus) {
+ if (jobStatus.shouldTreatAsUserInitiated()) {
+ return;
+ }
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
// If this method is called, then jobStatus.madeActive was never updated, so don't use it
@@ -384,6 +397,9 @@ public class TareController extends StateController {
@Override
@GuardedBy("mLock")
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
+ if (jobStatus.shouldTreatAsUserInitiated()) {
+ return;
+ }
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
if (!mTopStartedJobs.remove(jobStatus) && jobStatus.madeActive > 0) {
@@ -637,6 +653,10 @@ public class TareController extends StateController {
if (!mIsEnabled) {
return true;
}
+ if (jobStatus.shouldTreatAsUserInitiated()) {
+ // Always allow user-initiated jobs.
+ return true;
+ }
if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP
|| isTopStartedJobLocked(jobStatus)) {
// Jobs for the top app should always be allowed to run, and any jobs started while
diff --git a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
index 830031e2f442..85b762d1e524 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
@@ -91,12 +91,23 @@ public class ThermalStatusRestriction extends JobRestriction {
}
final int priority = job.getEffectivePriority();
if (mThermalStatus >= HIGHER_PRIORITY_THRESHOLD) {
- // For moderate throttling, only let expedited jobs and high priority regular jobs that
- // haven't been running for a long time run.
- return !job.shouldTreatAsExpeditedJob()
- && !(priority == JobInfo.PRIORITY_HIGH
- && mService.isCurrentlyRunningLocked(job)
- && !mService.isJobInOvertimeLocked(job));
+ // For moderate throttling:
+ // Only let expedited & user-initiated jobs run if:
+ // 1. They haven't previously run
+ // 2. They're already running and aren't yet in overtime
+ // Only let high priority jobs run if:
+ // They are already running and aren't yet in overtime
+ // Don't let any other job run.
+ if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiated()) {
+ return job.getNumPreviousAttempts() > 0
+ || (mService.isCurrentlyRunningLocked(job)
+ && mService.isJobInOvertimeLocked(job));
+ }
+ if (priority == JobInfo.PRIORITY_HIGH) {
+ return !mService.isCurrentlyRunningLocked(job)
+ || mService.isJobInOvertimeLocked(job);
+ }
+ return true;
}
if (mThermalStatus >= LOW_PRIORITY_THRESHOLD) {
// For light throttling, throttle all min priority jobs and all low priority jobs that
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 1a775b4e1d49..68699368dfb3 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2187,8 +2187,10 @@ public class AppStandbyController
}
// component-level enable/disable can affect bucketing, so we always
// reevaluate that for any PACKAGE_CHANGED
- mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkgName)
- .sendToTarget();
+ if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkgName)
+ .sendToTarget();
+ }
}
if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
Intent.ACTION_PACKAGE_ADDED.equals(action))) {
diff --git a/core/api/current.txt b/core/api/current.txt
index c1c4c92237db..3de345cd3ded 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -176,6 +176,8 @@ package android {
field public static final String REQUEST_COMPANION_PROFILE_APP_STREAMING = "android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING";
field public static final String REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION = "android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION";
field public static final String REQUEST_COMPANION_PROFILE_COMPUTER = "android.permission.REQUEST_COMPANION_PROFILE_COMPUTER";
+ field public static final String REQUEST_COMPANION_PROFILE_GLASSES = "android.permission.REQUEST_COMPANION_PROFILE_GLASSES";
+ field public static final String REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING = "android.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING";
field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
field public static final String REQUEST_COMPANION_SELF_MANAGED = "android.permission.REQUEST_COMPANION_SELF_MANAGED";
@@ -7283,7 +7285,9 @@ package android.app {
method public int getDesiredMinimumHeight();
method public int getDesiredMinimumWidth();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable getDrawable();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable getDrawable(int);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable getFastDrawable();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable getFastDrawable(int);
method public static android.app.WallpaperManager getInstance(android.content.Context);
method @Nullable public android.app.WallpaperColors getWallpaperColors(int);
method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.os.ParcelFileDescriptor getWallpaperFile(int);
@@ -7294,7 +7298,9 @@ package android.app {
method public boolean isSetWallpaperAllowed();
method public boolean isWallpaperSupported();
method @Nullable public android.graphics.drawable.Drawable peekDrawable();
+ method @Nullable public android.graphics.drawable.Drawable peekDrawable(int);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable peekFastDrawable();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable peekFastDrawable(int);
method public void removeOnColorsChangedListener(@NonNull android.app.WallpaperManager.OnColorsChangedListener);
method public void sendWallpaperCommand(android.os.IBinder, String, int, int, int, android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
@@ -9054,6 +9060,8 @@ package android.companion {
field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING) public static final String DEVICE_PROFILE_APP_STREAMING = "android.app.role.COMPANION_DEVICE_APP_STREAMING";
field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION) public static final String DEVICE_PROFILE_AUTOMOTIVE_PROJECTION = "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION";
field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER) public static final String DEVICE_PROFILE_COMPUTER = "android.app.role.COMPANION_DEVICE_COMPUTER";
+ field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_GLASSES) public static final String DEVICE_PROFILE_GLASSES = "android.app.role.COMPANION_DEVICE_GLASSES";
+ field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING) public static final String DEVICE_PROFILE_NEARBY_DEVICE_STREAMING = "android.app.role.COMPANION_DEVICE_NEARBY_DEVICE_STREAMING";
field public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
}
@@ -9173,8 +9181,8 @@ package android.companion.virtual {
public final class VirtualDeviceManager {
method @NonNull public java.util.List<android.companion.virtual.VirtualDevice> getVirtualDevices();
- field public static final int DEFAULT_DEVICE_ID = 0; // 0x0
- field public static final int INVALID_DEVICE_ID = -1; // 0xffffffff
+ field public static final int DEVICE_ID_DEFAULT = 0; // 0x0
+ field public static final int DEVICE_ID_INVALID = -1; // 0xffffffff
}
}
@@ -12495,7 +12503,7 @@ package android.content.pm {
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
field @RequiresPermission(android.Manifest.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT) public static final int FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT = 4096; // 0x1000
- field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
+ field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8
field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff
field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2
@@ -20549,10 +20557,12 @@ package android.media {
method public int abandonAudioFocusRequest(@NonNull android.media.AudioFocusRequest);
method public void addOnCommunicationDeviceChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnCommunicationDeviceChangedListener);
method public void addOnModeChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnModeChangedListener);
+ method public void addOnPreferredMixerAttributesChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredMixerAttributesChangedListener);
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
method public void clearCommunicationDevice();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public boolean clearPreferredMixerAttributes(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioDeviceInfo);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
@@ -20570,6 +20580,7 @@ package android.media {
method public int getMode();
method public String getParameters(String);
method @Deprecated public static int getPlaybackOffloadSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
+ method @Nullable public android.media.AudioMixerAttributes getPreferredMixerAttributes(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioDeviceInfo);
method public String getProperty(String);
method public int getRingerMode();
method @Deprecated public int getRouting(int);
@@ -20578,6 +20589,7 @@ package android.media {
method public int getStreamMinVolume(int);
method public int getStreamVolume(int);
method public float getStreamVolumeDb(int, int, int);
+ method @NonNull public java.util.List<android.media.AudioMixerAttributes> getSupportedMixerAttributes(@NonNull android.media.AudioDeviceInfo);
method @Deprecated public int getVibrateSetting(int);
method @Deprecated public boolean isBluetoothA2dpOn();
method public boolean isBluetoothScoAvailableOffCall();
@@ -20605,6 +20617,7 @@ package android.media {
method @Deprecated public boolean registerRemoteController(android.media.RemoteController);
method public void removeOnCommunicationDeviceChangedListener(@NonNull android.media.AudioManager.OnCommunicationDeviceChangedListener);
method public void removeOnModeChangedListener(@NonNull android.media.AudioManager.OnModeChangedListener);
+ method public void removeOnPreferredMixerAttributesChangedListener(@NonNull android.media.AudioManager.OnPreferredMixerAttributesChangedListener);
method @Deprecated public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
method public int requestAudioFocus(@NonNull android.media.AudioFocusRequest);
method public void setAllowedCapturePolicy(int);
@@ -20615,6 +20628,7 @@ package android.media {
method public void setMicrophoneMute(boolean);
method public void setMode(int);
method public void setParameters(String);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public boolean setPreferredMixerAttributes(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioDeviceInfo, @NonNull android.media.AudioMixerAttributes);
method public void setRingerMode(int);
method @Deprecated public void setRouting(int, int, int);
method @Deprecated public void setSpeakerphoneOn(boolean);
@@ -20770,6 +20784,10 @@ package android.media {
method public void onModeChanged(int);
}
+ public static interface AudioManager.OnPreferredMixerAttributesChangedListener {
+ method public void onPreferredMixerAttributesChanged(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioDeviceInfo, @Nullable android.media.AudioMixerAttributes);
+ }
+
public final class AudioMetadata {
method @NonNull public static android.media.AudioMetadataMap createMap();
}
@@ -20805,6 +20823,22 @@ package android.media {
method @IntRange(from=0) public int size();
}
+ public final class AudioMixerAttributes implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.media.AudioFormat getFormat();
+ method public int getMixerBehavior();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioMixerAttributes> CREATOR;
+ field public static final int MIXER_BEHAVIOR_BIT_PERFECT = 1; // 0x1
+ field public static final int MIXER_BEHAVIOR_DEFAULT = 0; // 0x0
+ }
+
+ public static final class AudioMixerAttributes.Builder {
+ ctor public AudioMixerAttributes.Builder(@NonNull android.media.AudioFormat);
+ method @NonNull public android.media.AudioMixerAttributes build();
+ method @NonNull public android.media.AudioMixerAttributes.Builder setMixerBehavior(int);
+ }
+
public final class AudioPlaybackCaptureConfiguration {
method @NonNull public int[] getExcludeUids();
method @NonNull public int[] getExcludeUsages();
@@ -24024,6 +24058,8 @@ package android.media {
method @NonNull public String getRouteId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteListingPreference.Item> CREATOR;
+ field public static final int DISABLE_REASON_AD = 3; // 0x3
+ field public static final int DISABLE_REASON_DOWNLOADED_CONTENT = 2; // 0x2
field public static final int DISABLE_REASON_NONE = 0; // 0x0
field public static final int DISABLE_REASON_SUBSCRIPTION_REQUIRED = 1; // 0x1
field public static final int FLAG_ONGOING_SESSION = 1; // 0x1
@@ -27815,6 +27851,7 @@ package android.net.vcn {
public final class VcnConfig implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.Set<android.net.vcn.VcnGatewayConnectionConfig> getGatewayConnectionConfigs();
+ method @NonNull public java.util.Set<java.lang.Integer> getRestrictedUnderlyingNetworkTransports();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnConfig> CREATOR;
}
@@ -27823,6 +27860,7 @@ package android.net.vcn {
ctor public VcnConfig.Builder(@NonNull android.content.Context);
method @NonNull public android.net.vcn.VcnConfig.Builder addGatewayConnectionConfig(@NonNull android.net.vcn.VcnGatewayConnectionConfig);
method @NonNull public android.net.vcn.VcnConfig build();
+ method @NonNull public android.net.vcn.VcnConfig.Builder setRestrictedUnderlyingNetworkTransports(@NonNull java.util.Set<java.lang.Integer>);
}
public final class VcnGatewayConnectionConfig {
@@ -38227,6 +38265,11 @@ package android.security.identity {
ctor public AlreadyPersonalizedException(@NonNull String, @NonNull Throwable);
}
+ public class AuthenticationKeyMetadata {
+ method @NonNull public java.time.Instant getExpirationDate();
+ method @IntRange(from=0) public int getUsageCount();
+ }
+
public class CipherSuiteNotSupportedException extends android.security.identity.IdentityCredentialException {
ctor public CipherSuiteNotSupportedException(@NonNull String);
ctor public CipherSuiteNotSupportedException(@NonNull String, @NonNull Throwable);
@@ -38257,6 +38300,7 @@ package android.security.identity {
public abstract class CredentialDataResult {
method @Nullable public abstract byte[] getDeviceMac();
method @NonNull public abstract byte[] getDeviceNameSpaces();
+ method @Nullable public byte[] getDeviceSignature();
method @NonNull public abstract android.security.identity.CredentialDataResult.Entries getDeviceSignedEntries();
method @NonNull public abstract android.security.identity.CredentialDataResult.Entries getIssuerSignedEntries();
method @NonNull public abstract byte[] getStaticAuthenticationData();
@@ -38293,13 +38337,15 @@ package android.security.identity {
method @NonNull public byte[] delete(@NonNull byte[]);
method @Deprecated @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]);
method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification();
- method @NonNull public abstract int[] getAuthenticationDataUsageCount();
+ method @Deprecated @NonNull public abstract int[] getAuthenticationDataUsageCount();
+ method @NonNull public java.util.List<android.security.identity.AuthenticationKeyMetadata> getAuthenticationKeyMetadata();
method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain();
method @Deprecated @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException;
method @NonNull public byte[] proveOwnership(@NonNull byte[]);
method @Deprecated public abstract void setAllowUsingExhaustedKeys(boolean);
method @Deprecated public void setAllowUsingExpiredKeys(boolean);
- method public abstract void setAvailableAuthenticationKeys(int, int);
+ method @Deprecated public abstract void setAvailableAuthenticationKeys(int, int);
+ method public void setAvailableAuthenticationKeys(@IntRange(from=0) int, @IntRange(from=1) int, @IntRange(from=0) long);
method @Deprecated public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException;
method @Deprecated public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
method public void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull java.time.Instant, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
@@ -39472,6 +39518,40 @@ package android.service.credentials {
method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.CreateEntry);
}
+ public final class BeginGetCredentialOption implements android.os.Parcelable {
+ ctor public BeginGetCredentialOption(@NonNull String, @NonNull android.os.Bundle);
+ method public int describeContents();
+ method @NonNull public android.os.Bundle getCandidateQueryData();
+ method @NonNull public String getType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialOption> CREATOR;
+ }
+
+ public final class BeginGetCredentialsRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<android.service.credentials.BeginGetCredentialOption> getBeginGetCredentialOptions();
+ method @NonNull public String getCallingPackage();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialsRequest> CREATOR;
+ }
+
+ public static final class BeginGetCredentialsRequest.Builder {
+ ctor public BeginGetCredentialsRequest.Builder(@NonNull String);
+ method @NonNull public android.service.credentials.BeginGetCredentialsRequest.Builder addBeginGetCredentialOption(@NonNull android.service.credentials.BeginGetCredentialOption);
+ method @NonNull public android.service.credentials.BeginGetCredentialsRequest build();
+ method @NonNull public android.service.credentials.BeginGetCredentialsRequest.Builder setBeginGetCredentialOptions(@NonNull java.util.List<android.service.credentials.BeginGetCredentialOption>);
+ }
+
+ public final class BeginGetCredentialsResponse implements android.os.Parcelable {
+ method @NonNull public static android.service.credentials.BeginGetCredentialsResponse createWithAuthentication(@NonNull android.service.credentials.Action);
+ method @NonNull public static android.service.credentials.BeginGetCredentialsResponse createWithResponseContent(@NonNull android.service.credentials.CredentialsResponseContent);
+ method public int describeContents();
+ method @Nullable public android.service.credentials.Action getAuthenticationAction();
+ method @Nullable public android.service.credentials.CredentialsResponseContent getCredentialsResponseContent();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialsResponse> CREATOR;
+ }
+
public final class CreateCredentialRequest implements android.os.Parcelable {
ctor public CreateCredentialRequest(@NonNull String, @NonNull String, @NonNull android.os.Bundle);
method public int describeContents();
@@ -39493,8 +39573,7 @@ package android.service.credentials {
public final class CredentialEntry implements android.os.Parcelable {
method public int describeContents();
- method @Nullable public android.credentials.Credential getCredential();
- method @Nullable public android.app.PendingIntent getPendingIntent();
+ method @NonNull public android.app.PendingIntent getPendingIntent();
method @NonNull public android.app.slice.Slice getSlice();
method @NonNull public String getType();
method public boolean isAutoSelectAllowed();
@@ -39504,7 +39583,6 @@ package android.service.credentials {
public static final class CredentialEntry.Builder {
ctor public CredentialEntry.Builder(@NonNull String, @NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent);
- ctor public CredentialEntry.Builder(@NonNull String, @NonNull android.app.slice.Slice, @NonNull android.credentials.Credential);
method @NonNull public android.service.credentials.CredentialEntry build();
method @NonNull public android.service.credentials.CredentialEntry.Builder setAutoSelectAllowed(@NonNull boolean);
}
@@ -39521,14 +39599,16 @@ package android.service.credentials {
public abstract class CredentialProviderService extends android.app.Service {
ctor public CredentialProviderService();
method public abstract void onBeginCreateCredential(@NonNull android.service.credentials.BeginCreateCredentialRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.service.credentials.CredentialProviderException>);
+ method public abstract void onBeginGetCredentials(@NonNull android.service.credentials.BeginGetCredentialsRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialsResponse,android.service.credentials.CredentialProviderException>);
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onGetCredentials(@NonNull android.service.credentials.GetCredentialsRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.GetCredentialsResponse,android.service.credentials.CredentialProviderException>);
field public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities";
+ field public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION = "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION";
field public static final String EXTRA_CREATE_CREDENTIAL_REQUEST = "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST";
- field public static final String EXTRA_CREATE_CREDENTIAL_RESULT = "android.service.credentials.extra.CREATE_CREDENTIAL_RESULT";
- field public static final String EXTRA_CREDENTIAL_RESULT = "android.service.credentials.extra.CREDENTIAL_RESULT";
- field public static final String EXTRA_ERROR = "android.service.credentials.extra.ERROR";
- field public static final String EXTRA_GET_CREDENTIALS_CONTENT_RESULT = "android.service.credentials.extra.GET_CREDENTIALS_CONTENT_RESULT";
+ field public static final String EXTRA_CREATE_CREDENTIAL_RESPONSE = "android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE";
+ field public static final String EXTRA_CREDENTIALS_RESPONSE_CONTENT = "android.service.credentials.extra.CREDENTIALS_RESPONSE_CONTENT";
+ field public static final String EXTRA_GET_CREDENTIAL_EXCEPTION = "android.service.credentials.extra.GET_CREDENTIAL_EXCEPTION";
+ field public static final String EXTRA_GET_CREDENTIAL_REQUEST = "android.service.credentials.extra.GET_CREDENTIAL_REQUEST";
+ field public static final String EXTRA_GET_CREDENTIAL_RESPONSE = "android.service.credentials.extra.GET_CREDENTIAL_RESPONSE";
field public static final String SERVICE_INTERFACE = "android.service.credentials.CredentialProviderService";
}
@@ -39551,29 +39631,19 @@ package android.service.credentials {
method @NonNull public android.service.credentials.CredentialsResponseContent.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.CredentialEntry);
}
- public final class GetCredentialsRequest implements android.os.Parcelable {
+ public final class GetCredentialRequest implements android.os.Parcelable {
method public int describeContents();
method @NonNull public String getCallingPackage();
method @NonNull public java.util.List<android.credentials.GetCredentialOption> getGetCredentialOptions();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialsRequest> CREATOR;
- }
-
- public static final class GetCredentialsRequest.Builder {
- ctor public GetCredentialsRequest.Builder(@NonNull String);
- method @NonNull public android.service.credentials.GetCredentialsRequest.Builder addGetCredentialOption(@NonNull android.credentials.GetCredentialOption);
- method @NonNull public android.service.credentials.GetCredentialsRequest build();
- method @NonNull public android.service.credentials.GetCredentialsRequest.Builder setGetCredentialOptions(@NonNull java.util.List<android.credentials.GetCredentialOption>);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialRequest> CREATOR;
}
- public final class GetCredentialsResponse implements android.os.Parcelable {
- method @NonNull public static android.service.credentials.GetCredentialsResponse createWithAuthentication(@NonNull android.service.credentials.Action);
- method @NonNull public static android.service.credentials.GetCredentialsResponse createWithResponseContent(@NonNull android.service.credentials.CredentialsResponseContent);
- method public int describeContents();
- method @Nullable public android.service.credentials.Action getAuthenticationAction();
- method @Nullable public android.service.credentials.CredentialsResponseContent getCredentialsResponseContent();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialsResponse> CREATOR;
+ public static final class GetCredentialRequest.Builder {
+ ctor public GetCredentialRequest.Builder(@NonNull String);
+ method @NonNull public android.service.credentials.GetCredentialRequest.Builder addGetCredentialOption(@NonNull android.credentials.GetCredentialOption);
+ method @NonNull public android.service.credentials.GetCredentialRequest build();
+ method @NonNull public android.service.credentials.GetCredentialRequest.Builder setGetCredentialOptions(@NonNull java.util.List<android.credentials.GetCredentialOption>);
}
}
@@ -41949,9 +42019,11 @@ package android.telephony {
}
public class CarrierConfigManager {
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfig();
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfig();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public android.os.PersistableBundle getConfig(@NonNull java.lang.String...);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigForSubId(int);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigForSubId(int);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public android.os.PersistableBundle getConfigForSubId(int, @NonNull java.lang.String...);
method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int);
field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
@@ -45375,6 +45447,7 @@ package android.telephony.ims.feature {
package android.telephony.ims.stub {
public class ImsRegistrationImplBase {
+ field public static final int REGISTRATION_TECH_3G = 4; // 0x4
field public static final int REGISTRATION_TECH_CROSS_SIM = 2; // 0x2
field public static final int REGISTRATION_TECH_IWLAN = 1; // 0x1
field public static final int REGISTRATION_TECH_LTE = 0; // 0x0
@@ -49495,6 +49568,7 @@ package android.view {
field public static final int KEYCODE_PROG_YELLOW = 185; // 0xb9
field public static final int KEYCODE_Q = 45; // 0x2d
field public static final int KEYCODE_R = 46; // 0x2e
+ field public static final int KEYCODE_RECENT_APPS = 312; // 0x138
field public static final int KEYCODE_REFRESH = 285; // 0x11d
field public static final int KEYCODE_RIGHT_BRACKET = 72; // 0x48
field public static final int KEYCODE_RO = 217; // 0xd9
@@ -52576,8 +52650,10 @@ package android.view {
}
public final class WindowMetrics {
- ctor public WindowMetrics(@NonNull android.graphics.Rect, @NonNull android.view.WindowInsets);
+ ctor @Deprecated public WindowMetrics(@NonNull android.graphics.Rect, @NonNull android.view.WindowInsets);
+ ctor public WindowMetrics(@NonNull android.graphics.Rect, @NonNull android.view.WindowInsets, float);
method @NonNull public android.graphics.Rect getBounds();
+ method public float getDensity();
method @NonNull public android.view.WindowInsets getWindowInsets();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 992e524d7edf..b3cbba2b95da 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -548,6 +548,8 @@ package android.app {
method @Nullable public static String opToPermission(@NonNull String);
method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int);
method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int);
+ method @RequiresPermission(value="android.permission.WATCH_APPOPS", conditional=true) public void startWatchingNoted(@NonNull String[], @NonNull android.app.AppOpsManager.OnOpNotedListener);
+ method public void stopWatchingNoted(@NonNull android.app.AppOpsManager.OnOpNotedListener);
field public static final int HISTORY_FLAGS_ALL = 3; // 0x3
field public static final int HISTORY_FLAG_AGGREGATE = 1; // 0x1
field public static final int HISTORY_FLAG_DISCRETE = 2; // 0x2
@@ -735,6 +737,10 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
}
+ public static interface AppOpsManager.OnOpNotedListener {
+ method public void onOpNoted(@NonNull String, int, @NonNull String, @Nullable String, int, int);
+ }
+
public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.AttributedOpEntry> getAttributedOpEntries();
@@ -3285,6 +3291,7 @@ package android.content {
field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
+ field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_DATA_SHARING_UPDATES = "android.intent.action.REVIEW_APP_DATA_SHARING_UPDATES";
field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_HISTORY = "android.intent.action.REVIEW_PERMISSION_HISTORY";
@@ -6246,6 +6253,7 @@ package android.location {
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
field public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED = "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
field public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
+ field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
}
public final class LocationRequest implements android.os.Parcelable {
@@ -6385,6 +6393,7 @@ package android.location.provider {
method public void setAllowed(boolean);
method public void setProperties(@NonNull android.location.provider.ProviderProperties);
field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
+ field public static final String ACTION_GNSS_PROVIDER = "android.location.provider.action.GNSS_PROVIDER";
field public static final String ACTION_NETWORK_PROVIDER = "com.android.location.service.v3.NetworkLocationProvider";
}
@@ -9695,6 +9704,8 @@ package android.os {
}
public class Environment {
+ method @NonNull public static java.io.File getDataCePackageDirectoryForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle, @NonNull String);
+ method @NonNull public static java.io.File getDataDePackageDirectoryForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle, @NonNull String);
method @NonNull public static java.util.Collection<java.io.File> getInternalMediaDirectories();
method @NonNull public static java.io.File getOdmDirectory();
method @NonNull public static java.io.File getOemDirectory();
@@ -15498,6 +15509,16 @@ package android.telephony.ims {
method public void onPublishStateChange(int);
}
+ public interface RegistrationManager {
+ field public static final int SUGGESTED_ACTION_NONE = 0; // 0x0
+ field public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK = 1; // 0x1
+ field public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT = 2; // 0x2
+ }
+
+ public static class RegistrationManager.RegistrationCallback {
+ method public void onUnregistered(@NonNull android.telephony.ims.ImsReasonInfo, int);
+ }
+
public final class RtpHeaderExtension implements android.os.Parcelable {
ctor public RtpHeaderExtension(@IntRange(from=1, to=14) int, @NonNull byte[]);
method public int describeContents();
@@ -15716,9 +15737,12 @@ package android.telephony.ims.feature {
method public void onFeatureRemoved();
method public boolean queryCapabilityConfiguration(int, int);
method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
+ method public final void setCallAudioHandler(int);
method public void setTerminalBasedCallWaitingStatus(boolean);
method public void setUiTtyMode(int, @Nullable android.os.Message);
method public int shouldProcessCall(@NonNull String[]);
+ field public static final int AUDIO_HANDLER_ANDROID = 0; // 0x0
+ field public static final int AUDIO_HANDLER_BASEBAND = 1; // 0x1
field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
field public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD";
field public static final int PROCESS_CALL_CSFB = 1; // 0x1
@@ -15894,6 +15918,7 @@ package android.telephony.ims.stub {
ctor public ImsRegistrationImplBase();
ctor public ImsRegistrationImplBase(@NonNull java.util.concurrent.Executor);
method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
+ method public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int);
method public final void onRegistered(int);
method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
method public final void onRegistering(int);
@@ -15911,6 +15936,7 @@ package android.telephony.ims.stub {
method public void acknowledgeSms(int, @IntRange(from=0, to=65535) int, int, @NonNull byte[]);
method public void acknowledgeSmsReport(int, @IntRange(from=0, to=65535) int, int);
method public String getSmsFormat();
+ method public void onMemoryAvailable(int);
method public void onReady();
method @Deprecated public final void onSendSmsResult(int, @IntRange(from=0, to=65535) int, int, int) throws java.lang.RuntimeException;
method public final void onSendSmsResultError(int, @IntRange(from=0, to=65535) int, int, int, int) throws java.lang.RuntimeException;
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 3d30c0f6d0b0..9730c169243c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -513,7 +513,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs();
method public void forceUpdateUserSetupComplete(int);
method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
- method public int getDeviceOwnerType(@NonNull android.content.ComponentName);
+ method @Deprecated public int getDeviceOwnerType(@NonNull android.content.ComponentName);
method @Nullable public String getDevicePolicyManagementRoleHolderUpdaterPackage();
method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
method public long getLastBugReportRequestTime();
@@ -1158,6 +1158,7 @@ package android.hardware.camera2 {
public final class CameraManager {
method public String[] getCameraIdListNoLazy() throws android.hardware.camera2.CameraAccessException;
method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
+ field public static final long OVERRIDE_FRONT_CAMERA_APP_COMPAT = 250678880L; // 0xef10e60L
}
public abstract static class CameraManager.AvailabilityCallback {
@@ -2070,7 +2071,7 @@ package android.os.storage {
public class StorageManager {
method public long computeStorageCacheBytes(@NonNull java.io.File);
- method @NonNull public static java.util.UUID convert(@NonNull String);
+ method @NonNull public static java.util.UUID convert(@Nullable String);
method @NonNull public static String convert(@NonNull java.util.UUID);
method @Nullable public String getCloudMediaProvider();
method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);
@@ -2637,6 +2638,8 @@ package android.telephony {
public final class SmsManager {
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int checkSmsShortCodeDestination(String, String);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearStorageMonitorMemoryStatusOverride();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setStorageMonitorMemoryStatusOverride(boolean);
field public static final int SMS_CATEGORY_FREE_SHORT_CODE = 1; // 0x1
field public static final int SMS_CATEGORY_NOT_SHORT_CODE = 0; // 0x0
field public static final int SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3; // 0x3
@@ -2927,7 +2930,7 @@ package android.view {
method public static String actionToString(int);
method public final void setDisplayId(int);
field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
- field public static final int LAST_KEYCODE = 311; // 0x137
+ field public static final int LAST_KEYCODE = 312; // 0x138
}
public final class KeyboardShortcutGroup implements android.os.Parcelable {
@@ -3433,14 +3436,20 @@ package android.window {
public class TaskFragmentOrganizer extends android.window.WindowOrganizer {
ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor);
+ method public void applyTransaction(@NonNull android.window.WindowContainerTransaction, int, boolean);
method @NonNull public java.util.concurrent.Executor getExecutor();
method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
+ method public void onTransactionHandled(@NonNull android.os.IBinder, @NonNull android.window.WindowContainerTransaction, int, boolean);
method public void onTransactionReady(@NonNull android.window.TaskFragmentTransaction);
method @CallSuper public void registerOrganizer();
method @CallSuper public void unregisterOrganizer();
field public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";
field public static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info";
field public static final String KEY_ERROR_CALLBACK_THROWABLE = "fragment_throwable";
+ field public static final int TASK_FRAGMENT_TRANSIT_CHANGE = 6; // 0x6
+ field public static final int TASK_FRAGMENT_TRANSIT_CLOSE = 2; // 0x2
+ field public static final int TASK_FRAGMENT_TRANSIT_NONE = 0; // 0x0
+ field public static final int TASK_FRAGMENT_TRANSIT_OPEN = 1; // 0x1
}
public final class TaskFragmentOrganizerToken implements android.os.Parcelable {
@@ -3562,8 +3571,8 @@ package android.window {
public class WindowOrganizer {
ctor public WindowOrganizer();
- method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback);
- method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public void applyTransaction(@NonNull android.window.WindowContainerTransaction);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction);
}
@UiContext public abstract class WindowProviderService extends android.app.Service {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 83963fd2141d..2d6eaf1d33eb 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -5305,6 +5305,38 @@ public class ActivityManager {
}
/**
+ * Delays delivering broadcasts to the specified package.
+ *
+ * <p> When {@code delayedDurationMs} is {@code 0}, it will clears any previously
+ * set forced delays.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ @IntRange(from = 0) long delayedDurationMs) {
+ try {
+ getService().forceDelayBroadcastDelivery(targetPackage, delayedDurationMs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Checks if the "modern" broadcast queue is enabled.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public boolean isModernBroadcastQueueEnabled() {
+ try {
+ return getService().isModernBroadcastQueueEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @return The reason code of whether or not the given UID should be exempted from background
* restrictions here.
*
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d5879fb523ce..563f6d4d9544 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -6844,22 +6844,52 @@ public class AppOpsManager {
}
/**
- * Callback for notification of an op being noted.
+ * Callback for notification of an app-op being noted.
*
* @hide
*/
+ @SystemApi
public interface OnOpNotedListener {
/**
- * Called when an op was noted.
- * @param code The op code.
+ * Called when an app-op is noted.
+ *
+ * @param op The operation that was noted.
* @param uid The UID performing the operation.
* @param packageName The package performing the operation.
* @param attributionTag The attribution tag performing the operation.
* @param flags The flags of this op
* @param result The result of the note.
*/
- void onOpNoted(int code, int uid, String packageName, String attributionTag,
- @OpFlags int flags, @Mode int result);
+ void onOpNoted(@NonNull String op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, @OpFlags int flags, @Mode int result);
+ }
+
+ /**
+ * Callback for notification of an app-op being noted to be used within platform code.
+ *
+ * This allows being notified using raw op codes instead of string op names.
+ *
+ * @hide
+ */
+ public interface OnOpNotedInternalListener extends OnOpNotedListener {
+ /**
+ * Called when an app-op is noted.
+ *
+ * @param code The code of the operation that was noted.
+ * @param uid The UID performing the operation.
+ * @param packageName The package performing the operation.
+ * @param attributionTag The attribution tag performing the operation.
+ * @param flags The flags of this op
+ * @param result The result of the note.
+ */
+ void onOpNoted(int code, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, @OpFlags int flags, @Mode int result);
+
+ @Override
+ default void onOpNoted(@NonNull String op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, @OpFlags int flags, @Mode int result) {
+ onOpNoted(strOpToOp(op), uid, packageName, attributionTag, flags, result);
+ }
}
/**
@@ -7654,13 +7684,42 @@ public class AppOpsManager {
* @param ops The ops to watch.
* @param callback Where to report changes.
*
- * @see #startWatchingActive(int[], OnOpActiveChangedListener)
- * @see #startWatchingStarted(int[], OnOpStartedListener)
* @see #stopWatchingNoted(OnOpNotedListener)
* @see #noteOp(String, int, String, String, String)
*
* @hide
*/
+ @SystemApi
+ @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
+ public void startWatchingNoted(@NonNull String[] ops, @NonNull OnOpNotedListener callback) {
+ final int[] intOps = new int[ops.length];
+ for (int i = 0; i < ops.length; i++) {
+ intOps[i] = strOpToOp(ops[i]);
+ }
+ startWatchingNoted(intOps, callback);
+ }
+
+ /**
+ * Start watching for noted app ops. An app op may be immediate or long running.
+ * Immediate ops are noted while long running ones are started and stopped. This
+ * method allows registering a listener to be notified when an app op is noted. If
+ * an op is being noted by any package you will get a callback. To change the
+ * watched ops for a registered callback you need to unregister and register it again.
+ *
+ * <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
+ * you can watch changes only for your UID.
+ *
+ * This allows observing noted ops by their raw op codes instead of string op names.
+ *
+ * @param ops The ops to watch.
+ * @param callback Where to report changes.
+ *
+ * @see #startWatchingActive(int[], OnOpActiveChangedListener)
+ * @see #startWatchingStarted(int[], OnOpStartedListener)
+ * @see #startWatchingNoted(String[], OnOpNotedListener)
+ *
+ * @hide
+ */
@RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingNoted(@NonNull int[] ops, @NonNull OnOpNotedListener callback) {
IAppOpsNotedCallback cb;
@@ -7673,7 +7732,10 @@ public class AppOpsManager {
@Override
public void opNoted(int op, int uid, String packageName, String attributionTag,
int flags, int mode) {
- callback.onOpNoted(op, uid, packageName, attributionTag, flags, mode);
+ if (sAppOpInfos[op].name != null) {
+ callback.onOpNoted(sAppOpInfos[op].name, uid, packageName, attributionTag,
+ flags, mode);
+ }
}
};
mNotedWatchers.put(callback, cb);
@@ -7689,11 +7751,12 @@ public class AppOpsManager {
* Stop watching for noted app ops. An app op may be immediate or long running.
* Unregistering a non-registered callback has no effect.
*
- * @see #startWatchingNoted(int[], OnOpNotedListener)
+ * @see #startWatchingNoted(String[], OnOpNotedListener)
* @see #noteOp(String, int, String, String, String)
*
* @hide
*/
+ @SystemApi
public void stopWatchingNoted(@NonNull OnOpNotedListener callback) {
synchronized (mNotedWatchers) {
final IAppOpsNotedCallback cb = mNotedWatchers.remove(callback);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 042bdd7e2ed5..39f71539b380 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -243,7 +243,7 @@ class ContextImpl extends Context {
@UnsupportedAppUsage
private @NonNull Resources mResources;
private @Nullable Display mDisplay; // may be null if invalid display or not initialized yet.
- private int mDeviceId = VirtualDeviceManager.DEFAULT_DEVICE_ID;
+ private int mDeviceId = VirtualDeviceManager.DEVICE_ID_DEFAULT;
/**
* If set to {@code true} the resources for this context will be configured for mDisplay which
@@ -2699,8 +2699,8 @@ class ContextImpl extends Context {
@Override
public @NonNull Context createDeviceContext(int deviceId) {
- boolean validDeviceId = deviceId == VirtualDeviceManager.DEFAULT_DEVICE_ID;
- if (deviceId > VirtualDeviceManager.DEFAULT_DEVICE_ID) {
+ boolean validDeviceId = deviceId == VirtualDeviceManager.DEVICE_ID_DEFAULT;
+ if (deviceId > VirtualDeviceManager.DEVICE_ID_DEFAULT) {
VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
if (vdm != null) {
List<VirtualDevice> virtualDevices = vdm.getVirtualDevices();
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index de0f7522f36d..411d157fa927 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -458,8 +458,7 @@ public class Dialog implements DialogInterface, Window.Callback,
&& WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// Add onBackPressed as default back behavior.
mDefaultBackCallback = this::onBackPressed;
- getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_DEFAULT, mDefaultBackCallback);
+ getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
mDefaultBackCallback = null;
}
}
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index e99e360a4583..877177cc8861 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -56,7 +56,6 @@ import android.content.pm.ServiceInfo.ForegroundServiceType;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
-import android.healthconnect.HealthConnectManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.permission.PermissionCheckerManager;
@@ -73,7 +72,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Optional;
-import java.util.Set;
/**
* This class enforces the policies around the foreground service types.
@@ -994,45 +992,6 @@ public abstract class ForegroundServiceTypePolicy {
}
}
- static class HealthConnectPermission extends RegularPermission {
- private @Nullable String[] mPermissionNames;
-
- HealthConnectPermission() {
- super("Health Connect");
- }
-
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- @PackageManager.PermissionResult
- public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
- String packageName, boolean allowWhileInUse) {
- final String[] perms = getPermissions(context);
- for (String perm : perms) {
- if (checkPermission(context, perm, callerUid, callerPid,
- packageName, allowWhileInUse) == PERMISSION_GRANTED) {
- return PERMISSION_GRANTED;
- }
- }
- return PERMISSION_DENIED;
- }
-
- @Override
- void addToList(@NonNull Context context, @NonNull ArrayList<String> list) {
- final String[] perms = getPermissions(context);
- for (String perm : perms) {
- list.add(perm);
- }
- }
-
- private @NonNull String[] getPermissions(@NonNull Context context) {
- if (mPermissionNames != null) {
- return mPermissionNames;
- }
- final Set<String> healthPerms = HealthConnectManager.getHealthPermissions(context);
- return mPermissionNames = healthPerms.toArray(new String[healthPerms.size()]);
- }
- }
-
/**
* The default policy for the foreground service types.
*
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 040111c78531..938f1f66a7d2 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -771,6 +771,14 @@ interface IActivityManager {
/** Blocks until all broadcast queues become idle. */
void waitForBroadcastIdle();
+ /** Delays delivering broadcasts to the specified package. */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.DUMP)")
+ void forceDelayBroadcastDelivery(in String targetPackage, long delayedDurationMs);
+
+ /** Checks if the modern broadcast queue is enabled. */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.DUMP)")
+ boolean isModernBroadcastQueueEnabled();
+
/**
* @return The reason code of whether or not the given UID should be exempted from background
* restrictions here.
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 91add2783c0d..f20503cef705 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -249,11 +249,6 @@ interface IActivityTaskManager {
/** Returns an interface enabling the management of window organizers. */
IWindowOrganizerController getWindowOrganizerController();
- /**
- * Sets whether we are currently in an interactive split screen resize operation where we
- * are changing the docked stack size.
- */
- void setSplitScreenResizing(boolean resizing);
boolean supportsLocalVoiceInteraction();
// Get device configuration
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index e8804328ef9d..84b404de9860 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -809,14 +809,7 @@ public class WallpaperManager {
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
@Nullable
public Drawable getDrawable() {
- final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
- if (bm != null) {
- Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
- dr.setDither(false);
- return dr;
- }
- return null;
+ return getDrawable(FLAG_SYSTEM);
}
/**
@@ -835,13 +828,20 @@ public class WallpaperManager {
* @return Returns a Drawable object that will draw the requested wallpaper,
* or {@code null} if the requested wallpaper does not exist or if the calling application
* is not able to access the wallpaper.
- * @hide
*/
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
@Nullable
public Drawable getDrawable(@SetWallpaperFlags int which) {
- return getDrawable();
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, which, cmProxy);
+ if (bm != null) {
+ Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+ dr.setDither(false);
+ return dr;
+ }
+ return null;
}
+
/**
* Obtain a drawable for the built-in static system wallpaper.
*/
@@ -1059,18 +1059,11 @@ public class WallpaperManager {
* wallpaper the user has currently set.
*
* @return Returns a Drawable object that will draw the wallpaper or a
- * null pointer if these is none.
+ * null pointer if wallpaper is unset.
*/
@Nullable
public Drawable peekDrawable() {
- final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
- if (bm != null) {
- Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
- dr.setDither(false);
- return dr;
- }
- return null;
+ return peekDrawable(FLAG_SYSTEM);
}
/**
@@ -1081,13 +1074,19 @@ public class WallpaperManager {
*
* @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
* IllegalArgumentException if an invalid wallpaper is requested.
- * @return Returns a Drawable object that will draw the wallpaper or a null pointer if these
- * is none.
- * @hide
+ * @return Returns a Drawable object that will draw the wallpaper or a null pointer if
+ * wallpaper is unset.
*/
@Nullable
public Drawable peekDrawable(@SetWallpaperFlags int which) {
- return peekDrawable();
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, which, cmProxy);
+ if (bm != null) {
+ Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
+ dr.setDither(false);
+ return dr;
+ }
+ return null;
}
/**
@@ -1106,12 +1105,7 @@ public class WallpaperManager {
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
@Nullable
public Drawable getFastDrawable() {
- final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
- if (bm != null) {
- return new FastBitmapDrawable(bm);
- }
- return null;
+ return getFastDrawable(FLAG_SYSTEM);
}
/**
@@ -1128,12 +1122,16 @@ public class WallpaperManager {
* @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
* IllegalArgumentException if an invalid wallpaper is requested.
* @return Returns a Drawable object that will draw the wallpaper.
- * @hide
*/
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
@Nullable
public Drawable getFastDrawable(@SetWallpaperFlags int which) {
- return getFastDrawable();
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, which, cmProxy);
+ if (bm != null) {
+ return new FastBitmapDrawable(bm);
+ }
+ return null;
}
/**
@@ -1146,12 +1144,7 @@ public class WallpaperManager {
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
@Nullable
public Drawable peekFastDrawable() {
- final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
- if (bm != null) {
- return new FastBitmapDrawable(bm);
- }
- return null;
+ return peekFastDrawable(FLAG_SYSTEM);
}
/**
@@ -1162,12 +1155,16 @@ public class WallpaperManager {
* IllegalArgumentException if an invalid wallpaper is requested.
* @return Returns an optimized Drawable object that will draw the
* wallpaper or a null pointer if these is none.
- * @hide
*/
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
@Nullable
public Drawable peekFastDrawable(@SetWallpaperFlags int which) {
- return peekFastDrawable();
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, which, cmProxy);
+ if (bm != null) {
+ return new FastBitmapDrawable(bm);
+ }
+ return null;
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index dd82bc1bc916..1e6412ff8a97 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -169,7 +169,12 @@ public class DevicePolicyManager {
public static final String DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_FLAG =
"deprecate_usermanagerinternal_devicepolicy";
/** @hide */
- public static final boolean DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_DEFAULT = false;
+ public static final boolean DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_DEFAULT = true;
+ /** @hide */
+ public static final String ADD_ISFINANCED_DEVICE_FLAG =
+ "add-isfinanced-device";
+ /** @hide */
+ public static final boolean ADD_ISFINANCED_FEVICE_DEFAULT = true;
private static String TAG = "DevicePolicyManager";
@@ -15425,10 +15430,13 @@ public class DevicePolicyManager {
*
* @throws IllegalStateException When admin is not the device owner or there is no device owner.
*
+ * @deprecated Use type-specific APIs (e.g. {@link #isFinancedDevice}).
* @hide
*/
@TestApi
@DeviceOwnerType
+ @Deprecated
+ // TODO(b/259908270): remove
public int getDeviceOwnerType(@NonNull ComponentName admin) {
throwIfParentInstance("getDeviceOwnerType");
if (mService != null) {
@@ -15442,6 +15450,20 @@ public class DevicePolicyManager {
}
/**
+ * {@code true} if this device is financed.
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+ })
+ public boolean isFinancedDevice() {
+ return isDeviceManaged()
+ && getDeviceOwnerType(getDeviceOwnerComponentOnAnyUser())
+ == DEVICE_OWNER_TYPE_FINANCED;
+ }
+
+ /**
* Called by device owner or profile owner of an organization-owned managed profile to
* enable or disable USB data signaling for the device. When disabled, USB data connections
* (except from charging functions) are prohibited.
diff --git a/core/java/android/app/time/TimeState.java b/core/java/android/app/time/TimeState.java
index c209cde2cf49..1d9add2c715f 100644
--- a/core/java/android/app/time/TimeState.java
+++ b/core/java/android/app/time/TimeState.java
@@ -29,11 +29,13 @@ import java.util.Objects;
/**
* A snapshot of the system time state.
*
- * <p>{@code mUnixEpochTime} contains a snapshot of the system clock time and elapsed realtime clock
+ * <p>{@code unixEpochTime} contains a snapshot of the system clock time and elapsed realtime clock
* time.
*
- * <p>{@code mUserShouldConfirmTime} is {@code true} if the system has low confidence in the system
- * clock time.
+ * <p>{@code userShouldConfirmTime} is {@code true} if the system automatic time detection logic
+ * suggests that the user be asked to confirm the {@code unixEpochTime} value is correct via {@link
+ * TimeManager#confirmTime}. If it is not correct, the value can usually be changed via {@link
+ * TimeManager#setManualTime}.
*
* @hide
*/
diff --git a/core/java/android/app/time/TimeZoneState.java b/core/java/android/app/time/TimeZoneState.java
index beb6dc6d1dfb..0febc34f1c37 100644
--- a/core/java/android/app/time/TimeZoneState.java
+++ b/core/java/android/app/time/TimeZoneState.java
@@ -32,8 +32,10 @@ import java.util.Objects;
* <p>{@code id} contains the system's time zone ID setting, e.g. "America/Los_Angeles". This
* will usually agree with {@code TimeZone.getDefault().getID()} but it can be empty in rare cases.
*
- * <p>{@code userShouldConfirmId} is {@code true} if the system has low confidence in the current
- * time zone.
+ * <p>{@code userShouldConfirmId} is {@code true} if the system automatic time zone detection logic
+ * suggests that the user be asked to confirm the {@code id} value is correct via {@link
+ * TimeManager#confirmTimeZone}. If it is not correct, the value can usually be changed via {@link
+ * TimeManager#setManualTimeZone}.
*
* @hide
*/
diff --git a/core/java/android/app/time/UnixEpochTime.java b/core/java/android/app/time/UnixEpochTime.java
index 3a35f3cd1acb..61cbc5ed7977 100644
--- a/core/java/android/app/time/UnixEpochTime.java
+++ b/core/java/android/app/time/UnixEpochTime.java
@@ -16,6 +16,7 @@
package android.app.time;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,7 +43,7 @@ import java.util.Objects;
@SystemApi
public final class UnixEpochTime implements Parcelable {
@ElapsedRealtimeLong private final long mElapsedRealtimeMillis;
- private final long mUnixEpochTimeMillis;
+ @CurrentTimeMillisLong private final long mUnixEpochTimeMillis;
public UnixEpochTime(@ElapsedRealtimeLong long elapsedRealtimeMillis,
long unixEpochTimeMillis) {
@@ -91,11 +92,13 @@ public final class UnixEpochTime implements Parcelable {
}
/** Returns the elapsed realtime clock value. See {@link UnixEpochTime} for more information. */
- public @ElapsedRealtimeLong long getElapsedRealtimeMillis() {
+ @ElapsedRealtimeLong
+ public long getElapsedRealtimeMillis() {
return mElapsedRealtimeMillis;
}
/** Returns the unix epoch time value. See {@link UnixEpochTime} for more information. */
+ @CurrentTimeMillisLong
public long getUnixEpochTimeMillis() {
return mUnixEpochTimeMillis;
}
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 3325d1eb2505..2e969f83f836 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -73,6 +73,21 @@ public final class AssociationRequest implements Parcelable {
public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
/**
+ * Device profile: glasses.
+ *
+ * If specified, the current request may have a modified UI to highlight that the device being
+ * set up is a glasses device, and some extra permissions may be granted to the app
+ * as a result.
+ *
+ * Using it requires declaring uses-permission
+ * {@link android.Manifest.permission#REQUEST_COMPANION_PROFILE_GLASSES} in the manifest.
+ *
+ * @see AssociationRequest.Builder#setDeviceProfile
+ */
+ @RequiresPermission(Manifest.permission.REQUEST_COMPANION_PROFILE_GLASSES)
+ public static final String DEVICE_PROFILE_GLASSES = "android.app.role.COMPANION_DEVICE_GLASSES";
+
+ /**
* Device profile: a virtual display capable of rendering Android applications, and sending back
* input events.
*
@@ -87,6 +102,20 @@ public final class AssociationRequest implements Parcelable {
"android.app.role.COMPANION_DEVICE_APP_STREAMING";
/**
+ * Device profile: a virtual device capable of rendering content from an Android host to a
+ * nearby device.
+ *
+ * Only applications that have been granted
+ * {@link android.Manifest.permission#REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING}
+ * are allowed to request to be associated with such devices.
+ *
+ * @see AssociationRequest.Builder#setDeviceProfile
+ */
+ @RequiresPermission(Manifest.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING)
+ public static final String DEVICE_PROFILE_NEARBY_DEVICE_STREAMING =
+ "android.app.role.COMPANION_DEVICE_NEARBY_DEVICE_STREAMING";
+
+ /**
* Device profile: Android Automotive Projection
*
* Only applications that have been granted
@@ -116,7 +145,8 @@ public final class AssociationRequest implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@StringDef(value = { DEVICE_PROFILE_WATCH, DEVICE_PROFILE_COMPUTER,
- DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, DEVICE_PROFILE_APP_STREAMING })
+ DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, DEVICE_PROFILE_APP_STREAMING,
+ DEVICE_PROFILE_GLASSES, DEVICE_PROFILE_NEARBY_DEVICE_STREAMING })
public @interface DeviceProfile {}
/**
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index 9e95d472f48b..f3f433540ef7 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -38,9 +38,9 @@ public final class VirtualDevice implements Parcelable {
* @hide
*/
public VirtualDevice(int id, @Nullable String name) {
- if (id <= VirtualDeviceManager.DEFAULT_DEVICE_ID) {
+ if (id <= VirtualDeviceManager.DEVICE_ID_DEFAULT) {
throw new IllegalArgumentException("VirtualDevice ID mist be greater than "
- + VirtualDeviceManager.DEFAULT_DEVICE_ID);
+ + VirtualDeviceManager.DEVICE_ID_DEFAULT);
}
mId = id;
mName = name;
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 109f4b1931f9..57bdf2d5212c 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -29,11 +29,14 @@ import android.app.PendingIntent;
import android.companion.AssociationInfo;
import android.companion.virtual.audio.VirtualAudioDevice;
import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
+import android.companion.virtual.camera.VirtualCameraDevice;
+import android.companion.virtual.camera.VirtualCameraInput;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Point;
+import android.hardware.camera2.CameraCharacteristics;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.VirtualDisplayFlag;
import android.hardware.display.DisplayManagerGlobal;
@@ -88,12 +91,12 @@ public final class VirtualDeviceManager {
/**
* The default device ID, which is the ID of the primary (non-virtual) device.
*/
- public static final int DEFAULT_DEVICE_ID = 0;
+ public static final int DEVICE_ID_DEFAULT = 0;
/**
* Invalid device ID.
*/
- public static final int INVALID_DEVICE_ID = -1;
+ public static final int DEVICE_ID_INVALID = -1;
/**
* Broadcast Action: A Virtual Device was removed.
@@ -238,7 +241,7 @@ public final class VirtualDeviceManager {
public int getDeviceIdForDisplayId(int displayId) {
if (mService == null) {
Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
- return DEFAULT_DEVICE_ID;
+ return DEVICE_ID_DEFAULT;
}
try {
return mService.getDeviceIdForDisplayId(displayId);
@@ -293,9 +296,11 @@ public final class VirtualDeviceManager {
}
};
@Nullable
- private VirtualAudioDevice mVirtualAudioDevice;
+ private VirtualCameraDevice mVirtualCameraDevice;
@NonNull
- private List<VirtualSensor> mVirtualSensors = new ArrayList<>();
+ private final List<VirtualSensor> mVirtualSensors = new ArrayList<>();
+ @Nullable
+ private VirtualAudioDevice mVirtualAudioDevice;
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
private VirtualDevice(
@@ -716,6 +721,34 @@ public final class VirtualDeviceManager {
}
/**
+ * Creates a new virtual camera. If a virtual camera was already created, it will be closed.
+ *
+ * @param cameraName name of the virtual camera.
+ * @param characteristics camera characteristics.
+ * @param virtualCameraInput callback that provides input to camera.
+ * @param executor Executor on which camera input will be sent into system. Don't
+ * use the Main Thread for this executor.
+ * @return newly created camera;
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ @NonNull
+ public VirtualCameraDevice createVirtualCameraDevice(
+ @NonNull String cameraName,
+ @NonNull CameraCharacteristics characteristics,
+ @NonNull VirtualCameraInput virtualCameraInput,
+ @NonNull Executor executor) {
+ if (mVirtualCameraDevice != null) {
+ mVirtualCameraDevice.close();
+ }
+ int deviceId = getDeviceId();
+ mVirtualCameraDevice = new VirtualCameraDevice(
+ deviceId, cameraName, characteristics, virtualCameraInput, executor);
+ return mVirtualCameraDevice;
+ }
+
+ /**
* Sets the visibility of the pointer icon for this VirtualDevice's associated displays.
*
* @param showPointerIcon True if the pointer should be shown; false otherwise. The default
diff --git a/core/java/android/companion/virtual/camera/VirtualCameraDevice.java b/core/java/android/companion/virtual/camera/VirtualCameraDevice.java
new file mode 100644
index 000000000000..a7eba873445c
--- /dev/null
+++ b/core/java/android/companion/virtual/camera/VirtualCameraDevice.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.camera;
+
+import android.hardware.camera2.CameraCharacteristics;
+
+import androidx.annotation.NonNull;
+
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Virtual camera that is used to send image data into system.
+ *
+ * @hide
+ */
+public final class VirtualCameraDevice implements AutoCloseable {
+
+ @NonNull
+ private final String mCameraDeviceName;
+ @NonNull
+ private final CameraCharacteristics mCameraCharacteristics;
+ @NonNull
+ private final VirtualCameraOutput mCameraOutput;
+ private boolean mCameraRegistered = false;
+
+ /**
+ * VirtualCamera device constructor.
+ *
+ * @param virtualDeviceId ID of virtual device to which camera will be added.
+ * @param cameraName must be unique for each camera per virtual device.
+ * @param characteristics of camera that will be passed into system in order to describe
+ * camera.
+ * @param virtualCameraInput component that provides image data.
+ * @param executor on which to collect image data and pass it into system.
+ */
+ public VirtualCameraDevice(int virtualDeviceId, @NonNull String cameraName,
+ @NonNull CameraCharacteristics characteristics,
+ @NonNull VirtualCameraInput virtualCameraInput, @NonNull Executor executor) {
+ Objects.requireNonNull(cameraName);
+ mCameraCharacteristics = Objects.requireNonNull(characteristics);
+ mCameraDeviceName = generateCameraDeviceName(virtualDeviceId, cameraName);
+ mCameraOutput = new VirtualCameraOutput(virtualCameraInput, executor);
+ registerCamera();
+ }
+
+ private static String generateCameraDeviceName(int deviceId, @NonNull String cameraName) {
+ return String.format(Locale.ENGLISH, "%d_%s", deviceId, Objects.requireNonNull(cameraName));
+ }
+
+ @Override
+ public void close() {
+ if (!mCameraRegistered) {
+ return;
+ }
+
+ mCameraOutput.closeStream();
+ }
+
+ private void registerCamera() {
+ if (mCameraRegistered) {
+ return;
+ }
+
+ mCameraRegistered = true;
+ }
+}
diff --git a/core/java/android/companion/virtual/camera/VirtualCameraInput.java b/core/java/android/companion/virtual/camera/VirtualCameraInput.java
new file mode 100644
index 000000000000..690a64b7fd23
--- /dev/null
+++ b/core/java/android/companion/virtual/camera/VirtualCameraInput.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.camera;
+
+import android.annotation.NonNull;
+import android.hardware.camera2.params.InputConfiguration;
+
+import java.io.InputStream;
+
+/***
+ * Used for sending image data into virtual camera.
+ * <p>
+ * The system will call {@link #openStream(InputConfiguration)} to signal when you
+ * should start sending Camera image data.
+ * When Camera is no longer needed, or there is change in configuration
+ * {@link #closeStream()} will be called. At that time finish sending current
+ * image data and then close the stream.
+ * <p>
+ * If Camera image data is needed again, {@link #openStream(InputConfiguration)} will be
+ * called by the system.
+ *
+ * @hide
+ */
+public interface VirtualCameraInput {
+
+ /**
+ * Opens a new image stream for the provided {@link InputConfiguration}.
+ *
+ * @param inputConfiguration image data configuration.
+ * @return image data stream.
+ */
+ @NonNull
+ InputStream openStream(@NonNull InputConfiguration inputConfiguration);
+
+ /**
+ * Stop sending image data and close {@link InputStream} provided in {@link
+ * #openStream(InputConfiguration)}. Do nothing if there is currently no active stream.
+ */
+ void closeStream();
+}
diff --git a/core/java/android/companion/virtual/camera/VirtualCameraOutput.java b/core/java/android/companion/virtual/camera/VirtualCameraOutput.java
new file mode 100644
index 000000000000..fa1c3ad23ab8
--- /dev/null
+++ b/core/java/android/companion/virtual/camera/VirtualCameraOutput.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.camera;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.camera2.params.InputConfiguration;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Component for providing Camera data to the system.
+ * <p>
+ * {@link #getStreamDescriptor(InputConfiguration)} will be called by the system when Camera should
+ * start sending image data. Camera data will continue to be sent into {@link ParcelFileDescriptor}
+ * until {@link #closeStream()} is called by the system, at which point {@link ParcelFileDescriptor}
+ * will be closed.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class VirtualCameraOutput {
+
+ private static final String TAG = "VirtualCameraDeviceImpl";
+
+ @NonNull
+ private final VirtualCameraInput mVirtualCameraInput;
+ @NonNull
+ private final Executor mExecutor;
+ @Nullable
+ private VirtualCameraStream mCameraStream;
+
+ @VisibleForTesting
+ public VirtualCameraOutput(@NonNull VirtualCameraInput cameraInput,
+ @NonNull Executor executor) {
+ mVirtualCameraInput = Objects.requireNonNull(cameraInput);
+ mExecutor = Objects.requireNonNull(executor);
+ }
+
+ /**
+ * Get a read Descriptor on which Camera HAL will receive data. At any point in time there can
+ * exist a maximum of one active {@link ParcelFileDescriptor}.
+ * Calling this method with a different {@link InputConfiguration} is going to close the
+ * previously created file descriptor.
+ *
+ * @param imageConfiguration for which to create the {@link ParcelFileDescriptor}.
+ * @return Newly created ParcelFileDescriptor if stream param is different from previous or if
+ * this is first time call. Will return null if there was an error during Descriptor
+ * creation process.
+ */
+ @Nullable
+ @VisibleForTesting
+ public ParcelFileDescriptor getStreamDescriptor(
+ @NonNull InputConfiguration imageConfiguration) {
+ Objects.requireNonNull(imageConfiguration);
+
+ // Reuse same descriptor if stream is the same, otherwise create a new one.
+ try {
+ if (mCameraStream == null) {
+ mCameraStream = new VirtualCameraStream(imageConfiguration, mExecutor);
+ } else if (!mCameraStream.isSameConfiguration(imageConfiguration)) {
+ mCameraStream.close();
+ mCameraStream = new VirtualCameraStream(imageConfiguration, mExecutor);
+ }
+ } catch (IOException exception) {
+ Log.e(TAG, "Unable to open file descriptor.", exception);
+ return null;
+ }
+
+ InputStream imageStream = mVirtualCameraInput.openStream(imageConfiguration);
+ mCameraStream.startSending(imageStream);
+ return mCameraStream.getDescriptor();
+ }
+
+ /**
+ * Closes currently opened stream. If there is no stream, do nothing.
+ */
+ @VisibleForTesting
+ public void closeStream() {
+ mVirtualCameraInput.closeStream();
+ if (mCameraStream != null) {
+ mCameraStream.close();
+ mCameraStream = null;
+ }
+
+ try {
+ mVirtualCameraInput.closeStream();
+ } catch (Exception e) {
+ Log.e(TAG, "Error during closing stream.", e);
+ }
+ }
+
+ private static class VirtualCameraStream implements AutoCloseable {
+
+ private static final String TAG = "VirtualCameraStream";
+ private static final int BUFFER_SIZE = 1024;
+
+ private static final int SENDING_STATE_INITIAL = 0;
+ private static final int SENDING_STATE_IN_PROGRESS = 1;
+ private static final int SENDING_STATE_CLOSED = 2;
+
+ @NonNull
+ private final InputConfiguration mImageConfiguration;
+ @NonNull
+ private final Executor mExecutor;
+ @Nullable
+ private final ParcelFileDescriptor mReadDescriptor;
+ @Nullable
+ private final ParcelFileDescriptor mWriteDescriptor;
+ private int mSendingState;
+
+ VirtualCameraStream(@NonNull InputConfiguration imageConfiguration,
+ @NonNull Executor executor) throws IOException {
+ mSendingState = SENDING_STATE_INITIAL;
+ mImageConfiguration = Objects.requireNonNull(imageConfiguration);
+ mExecutor = Objects.requireNonNull(executor);
+ ParcelFileDescriptor[] parcels = ParcelFileDescriptor.createPipe();
+ mReadDescriptor = parcels[0];
+ mWriteDescriptor = parcels[1];
+ }
+
+ boolean isSameConfiguration(@NonNull InputConfiguration imageConfiguration) {
+ return mImageConfiguration == Objects.requireNonNull(imageConfiguration);
+ }
+
+ @Nullable
+ ParcelFileDescriptor getDescriptor() {
+ return mReadDescriptor;
+ }
+
+ public void startSending(@NonNull InputStream inputStream) {
+ Objects.requireNonNull(inputStream);
+
+ if (mSendingState != SENDING_STATE_INITIAL) {
+ return;
+ }
+
+ mSendingState = SENDING_STATE_IN_PROGRESS;
+ mExecutor.execute(() -> sendData(inputStream));
+ }
+
+ @Override
+ public void close() {
+ mSendingState = SENDING_STATE_CLOSED;
+ try {
+ mReadDescriptor.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to close read descriptor.", e);
+ }
+ try {
+ mWriteDescriptor.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to close write descriptor.", e);
+ }
+ }
+
+ private void sendData(@NonNull InputStream inputStream) {
+ Objects.requireNonNull(inputStream);
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+ FileDescriptor fd = mWriteDescriptor.getFileDescriptor();
+ try (FileOutputStream outputStream = new FileOutputStream(fd)) {
+ while (mSendingState == SENDING_STATE_IN_PROGRESS) {
+ int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+ if (bytesRead < 1) continue;
+
+ outputStream.write(buffer, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error while sending camera data.", e);
+ }
+ }
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index df5a1ed661cd..382e2bb6ee43 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6903,7 +6903,7 @@ public abstract class Context {
* <p>
* Applications that run on virtual devices may use this method to access the default device
* capabilities and functionality (by passing
- * {@link android.companion.virtual.VirtualDeviceManager#DEFAULT_DEVICE_ID}. Similarly,
+ * {@link android.companion.virtual.VirtualDeviceManager#DEVICE_ID_DEFAULT}. Similarly,
* applications running on the default device may access the functionality of virtual devices.
* </p>
* @param deviceId The ID of the device to associate with this context.
@@ -7245,7 +7245,7 @@ public abstract class Context {
* determine whether they are running on a virtual device and identify that device.
*
* The device ID of the host device is
- * {@link android.companion.virtual.VirtualDeviceManager#DEFAULT_DEVICE_ID}
+ * {@link android.companion.virtual.VirtualDeviceManager#DEVICE_ID_DEFAULT}
*
* @return the ID of the device this context is associated with.
* @see #createDeviceContext(int)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 86a672f1d67e..ebc00a7dea25 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2422,6 +2422,30 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_SAFETY_CENTER =
"android.intent.action.SAFETY_CENTER";
+ /**
+ * Activity action: Launch the UI to view recent updates that installed apps have made to their
+ * data sharing policy in their safety labels.
+ *
+ * <p>
+ * Input: Nothing.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * <p class="note">
+ * This intent action requires the {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS}
+ * permission.
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REVIEW_APP_DATA_SHARING_UPDATES =
+ "android.intent.action.REVIEW_APP_DATA_SHARING_UPDATES";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent broadcast actions (see action variable).
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index fc2c532ee756..6453ab0b8964 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -308,9 +308,7 @@ public class ServiceInfo extends ComponentInfo
* permissions:
* {@link android.Manifest.permission#ACTIVITY_RECOGNITION},
* {@link android.Manifest.permission#BODY_SENSORS},
- * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS},
- * or one of the {@code "android.permission.health.*"} permissions defined in the
- * {@link android.healthconnect.HealthPermissions}.
+ * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}.
*/
@RequiresPermission(
allOf = {
@@ -320,8 +318,7 @@ public class ServiceInfo extends ComponentInfo
Manifest.permission.ACTIVITY_RECOGNITION,
Manifest.permission.BODY_SENSORS,
Manifest.permission.HIGH_SAMPLING_RATE_SENSORS,
- },
- conditional = true
+ }
)
public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 1 << 8;
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index fd35378efba2..fb61b3769e98 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -46,6 +46,8 @@ public final class UserProperties implements Parcelable {
private static final String ATTR_SHOW_IN_SETTINGS = "showInSettings";
private static final String ATTR_INHERIT_DEVICE_POLICY = "inheritDevicePolicy";
private static final String ATTR_USE_PARENTS_CONTACTS = "useParentsContacts";
+ private static final String ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA =
+ "updateCrossProfileIntentFiltersOnOTA";
/** Index values of each property (to indicate whether they are present in this object). */
@IntDef(prefix = "INDEX_", value = {
@@ -54,6 +56,7 @@ public final class UserProperties implements Parcelable {
INDEX_SHOW_IN_SETTINGS,
INDEX_INHERIT_DEVICE_POLICY,
INDEX_USE_PARENTS_CONTACTS,
+ INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA
})
@Retention(RetentionPolicy.SOURCE)
private @interface PropertyIndex {
@@ -63,6 +66,7 @@ public final class UserProperties implements Parcelable {
private static final int INDEX_SHOW_IN_SETTINGS = 2;
private static final int INDEX_INHERIT_DEVICE_POLICY = 3;
private static final int INDEX_USE_PARENTS_CONTACTS = 4;
+ private static final int INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA = 5;
/** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
private long mPropertiesPresent = 0;
@@ -199,6 +203,7 @@ public final class UserProperties implements Parcelable {
// Add items that require exposeAllFields to be true (strictest permission level).
setStartWithParent(orig.getStartWithParent());
setInheritDevicePolicy(orig.getInheritDevicePolicy());
+ setUpdateCrossProfileIntentFiltersOnOTA(orig.getUpdateCrossProfileIntentFiltersOnOTA());
}
if (hasManagePermission) {
// Add items that require MANAGE_USERS or stronger.
@@ -354,6 +359,34 @@ public final class UserProperties implements Parcelable {
*/
private boolean mUseParentsContacts;
+ /**
+ * Returns true if user needs to update default
+ * {@link com.android.server.pm.CrossProfileIntentFilter} with its parents during an OTA update
+ * @hide
+ */
+ public boolean getUpdateCrossProfileIntentFiltersOnOTA() {
+ if (isPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA)) {
+ return mUpdateCrossProfileIntentFiltersOnOTA;
+ }
+ if (mDefaultProperties != null) {
+ return mDefaultProperties.mUpdateCrossProfileIntentFiltersOnOTA;
+ }
+ throw new SecurityException("You don't have permission to query "
+ + "updateCrossProfileIntentFiltersOnOTA");
+ }
+
+ /** @hide */
+ public void setUpdateCrossProfileIntentFiltersOnOTA(boolean val) {
+ this.mUpdateCrossProfileIntentFiltersOnOTA = val;
+ setPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA);
+ }
+
+ /*
+ Indicate if {@link com.android.server.pm.CrossProfileIntentFilter}s need to be updated during
+ OTA update between user-parent
+ */
+ private boolean mUpdateCrossProfileIntentFiltersOnOTA;
+
@Override
public String toString() {
// Please print in increasing order of PropertyIndex.
@@ -364,6 +397,8 @@ public final class UserProperties implements Parcelable {
+ ", mShowInSettings=" + getShowInSettings()
+ ", mInheritDevicePolicy=" + getInheritDevicePolicy()
+ ", mUseParentsContacts=" + getUseParentsContacts()
+ + ", mUpdateCrossProfileIntentFiltersOnOTA="
+ + getUpdateCrossProfileIntentFiltersOnOTA()
+ "}";
}
@@ -380,6 +415,8 @@ public final class UserProperties implements Parcelable {
pw.println(prefix + " mShowInSettings=" + getShowInSettings());
pw.println(prefix + " mInheritDevicePolicy=" + getInheritDevicePolicy());
pw.println(prefix + " mUseParentsContacts=" + getUseParentsContacts());
+ pw.println(prefix + " mUpdateCrossProfileIntentFiltersOnOTA="
+ + getUpdateCrossProfileIntentFiltersOnOTA());
}
/**
@@ -428,6 +465,9 @@ public final class UserProperties implements Parcelable {
case ATTR_USE_PARENTS_CONTACTS:
setUseParentsContacts(parser.getAttributeBoolean(i));
break;
+ case ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA:
+ setUpdateCrossProfileIntentFiltersOnOTA(parser.getAttributeBoolean(i));
+ break;
default:
Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
}
@@ -462,6 +502,11 @@ public final class UserProperties implements Parcelable {
serializer.attributeBoolean(null, ATTR_USE_PARENTS_CONTACTS,
mUseParentsContacts);
}
+ if (isPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA)) {
+ serializer.attributeBoolean(null,
+ ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA,
+ mUpdateCrossProfileIntentFiltersOnOTA);
+ }
}
// For use only with an object that has already had any permission-lacking fields stripped out.
@@ -473,6 +518,7 @@ public final class UserProperties implements Parcelable {
dest.writeInt(mShowInSettings);
dest.writeInt(mInheritDevicePolicy);
dest.writeBoolean(mUseParentsContacts);
+ dest.writeBoolean(mUpdateCrossProfileIntentFiltersOnOTA);
}
/**
@@ -488,6 +534,7 @@ public final class UserProperties implements Parcelable {
mShowInSettings = source.readInt();
mInheritDevicePolicy = source.readInt();
mUseParentsContacts = source.readBoolean();
+ mUpdateCrossProfileIntentFiltersOnOTA = source.readBoolean();
}
@Override
@@ -517,6 +564,7 @@ public final class UserProperties implements Parcelable {
private @ShowInSettings int mShowInSettings = SHOW_IN_SETTINGS_WITH_PARENT;
private @InheritDevicePolicy int mInheritDevicePolicy = INHERIT_DEVICE_POLICY_NO;
private boolean mUseParentsContacts = false;
+ private boolean mUpdateCrossProfileIntentFiltersOnOTA = false;
public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
mShowInLauncher = showInLauncher;
@@ -546,6 +594,13 @@ public final class UserProperties implements Parcelable {
return this;
}
+ /** Sets the value for {@link #mUpdateCrossProfileIntentFiltersOnOTA} */
+ public Builder setUpdateCrossProfileIntentFiltersOnOTA(boolean
+ updateCrossProfileIntentFiltersOnOTA) {
+ mUpdateCrossProfileIntentFiltersOnOTA = updateCrossProfileIntentFiltersOnOTA;
+ return this;
+ }
+
/** Builds a UserProperties object with *all* values populated. */
public UserProperties build() {
return new UserProperties(
@@ -553,7 +608,8 @@ public final class UserProperties implements Parcelable {
mStartWithParent,
mShowInSettings,
mInheritDevicePolicy,
- mUseParentsContacts);
+ mUseParentsContacts,
+ mUpdateCrossProfileIntentFiltersOnOTA);
}
} // end Builder
@@ -563,7 +619,7 @@ public final class UserProperties implements Parcelable {
boolean startWithParent,
@ShowInSettings int showInSettings,
@InheritDevicePolicy int inheritDevicePolicy,
- boolean useParentsContacts) {
+ boolean useParentsContacts, boolean updateCrossProfileIntentFiltersOnOTA) {
mDefaultProperties = null;
setShowInLauncher(showInLauncher);
@@ -571,5 +627,6 @@ public final class UserProperties implements Parcelable {
setShowInSettings(showInSettings);
setInheritDevicePolicy(inheritDevicePolicy);
setUseParentsContacts(useParentsContacts);
+ setUpdateCrossProfileIntentFiltersOnOTA(updateCrossProfileIntentFiltersOnOTA);
}
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index fb1fcf8e2a06..d6934bca46b7 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -43,6 +43,7 @@ import android.annotation.StyleableRes;
import android.annotation.XmlRes;
import android.app.Application;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
import android.content.res.loader.ResourcesLoader;
@@ -2181,17 +2182,19 @@ public class Resources {
}
/**
- * Return the current display metrics that are in effect for this resource
+ * Returns the current display metrics that are in effect for this resource
* object. The returned object should be treated as read-only.
*
* <p>Note that the reported value may be different than the window this application is
* interested in.</p>
*
- * <p>Best practices are to obtain metrics from {@link WindowManager#getCurrentWindowMetrics()}
- * for window bounds, {@link Display#getRealMetrics(DisplayMetrics)} for display bounds and
- * obtain density from {@link Configuration#densityDpi}. The value obtained from this API may be
- * wrong if the {@link Resources} is from the context which is different than the window is
- * attached such as {@link Application#getResources()}.
+ * <p>The best practices is to obtain metrics from
+ * {@link WindowManager#getCurrentWindowMetrics()} for window bounds. The value obtained from
+ * this API may be wrong if {@link Context#getResources()} is from
+ * non-{@link android.annotation.UiContext}.
+ * For example, use the {@link DisplayMetrics} obtained from {@link Application#getResources()}
+ * to build {@link android.app.Activity} UI elements especially when the
+ * {@link android.app.Activity} is in the multi-window mode or on the secondary {@link Display}.
* <p/>
*
* @return The resource's current display metrics.
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index c011949ec6d4..49e849523de2 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -21,6 +21,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.app.Activity;
import android.app.PendingIntent;
@@ -32,6 +33,7 @@ import android.os.OutcomeReceiver;
import android.os.RemoteException;
import android.util.Log;
+import java.util.List;
import java.util.concurrent.Executor;
/**
@@ -40,9 +42,9 @@ import java.util.concurrent.Executor;
* <p>Note that an application should call the Jetpack CredentialManager apis instead of directly
* calling these framework apis.
*
- * <p>The CredentialManager apis launch framework UI flows for a user to
- * register a new credential or to consent to a saved credential from supported credential
- * providers, which can then be used to authenticate to the app.
+ * <p>The CredentialManager apis launch framework UI flows for a user to register a new credential
+ * or to consent to a saved credential from supported credential providers, which can then be used
+ * to authenticate to the app.
*/
@SystemService(Context.CREDENTIAL_SERVICE)
public final class CredentialManager {
@@ -76,8 +78,7 @@ public final class CredentialManager {
@NonNull Activity activity,
@Nullable CancellationSignal cancellationSignal,
@CallbackExecutor @NonNull Executor executor,
- @NonNull OutcomeReceiver<
- GetCredentialResponse, GetCredentialException> callback) {
+ @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
requireNonNull(request, "request must not be null");
requireNonNull(activity, "activity must not be null");
requireNonNull(executor, "executor must not be null");
@@ -90,10 +91,11 @@ public final class CredentialManager {
ICancellationSignal cancelRemote = null;
try {
- cancelRemote = mService.executeGetCredential(
- request,
- new GetCredentialTransport(activity, executor, callback),
- mContext.getOpPackageName());
+ cancelRemote =
+ mService.executeGetCredential(
+ request,
+ new GetCredentialTransport(activity, executor, callback),
+ mContext.getOpPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -106,8 +108,8 @@ public final class CredentialManager {
/**
* Launches the necessary flows to register an app credential for the user.
*
- * <p>The execution can potentially launch UI flows to collect user consent to creating
- * or storing the new credential, etc.
+ * <p>The execution can potentially launch UI flows to collect user consent to creating or
+ * storing the new credential, etc.
*
* @param request the request specifying type(s) of credentials to get from the user
* @param activity the activity used to launch any UI needed
@@ -120,8 +122,8 @@ public final class CredentialManager {
@NonNull Activity activity,
@Nullable CancellationSignal cancellationSignal,
@CallbackExecutor @NonNull Executor executor,
- @NonNull OutcomeReceiver<
- CreateCredentialResponse, CreateCredentialException> callback) {
+ @NonNull
+ OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback) {
requireNonNull(request, "request must not be null");
requireNonNull(activity, "activity must not be null");
requireNonNull(executor, "executor must not be null");
@@ -134,9 +136,11 @@ public final class CredentialManager {
ICancellationSignal cancelRemote = null;
try {
- cancelRemote = mService.executeCreateCredential(request,
- new CreateCredentialTransport(activity, executor, callback),
- mContext.getOpPackageName());
+ cancelRemote =
+ mService.executeCreateCredential(
+ request,
+ new CreateCredentialTransport(activity, executor, callback),
+ mContext.getOpPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -149,10 +153,10 @@ public final class CredentialManager {
/**
* Clears the current user credential state from all credential providers.
*
- * You should invoked this api after your user signs out of your app to notify all credential
+ * <p>You should invoked this api after your user signs out of your app to notify all credential
* providers that any stored credential session for the given app should be cleared.
*
- * A credential provider may have stored an active credential session and use it to limit
+ * <p>A credential provider may have stored an active credential session and use it to limit
* sign-in options for future get-credential calls. For example, it may prioritize the active
* credential over any other available credential. When your user explicitly signs out of your
* app and in order to get the holistic sign-in options the next time, you should call this API
@@ -178,9 +182,11 @@ public final class CredentialManager {
ICancellationSignal cancelRemote = null;
try {
- cancelRemote = mService.clearCredentialState(request,
- new ClearCredentialStateTransport(executor, callback),
- mContext.getOpPackageName());
+ cancelRemote =
+ mService.clearCredentialState(
+ request,
+ new ClearCredentialStateTransport(executor, callback),
+ mContext.getOpPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -190,15 +196,86 @@ public final class CredentialManager {
}
}
+ /**
+ * Gets a list of all user configurable credential providers registered on the system. This API
+ * is intended for browsers and settings apps.
+ *
+ * @param cancellationSignal an optional signal that allows for cancelling this call
+ * @param executor the callback will take place on this {@link Executor}
+ * @param callback the callback invoked when the request succeeds or fails
+ * @hide
+ */
+ @RequiresPermission(
+ allOf = {
+ android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS,
+ android.Manifest.permission.QUERY_ALL_PACKAGES
+ })
+ public void listEnabledProviders(
+ @Nullable CancellationSignal cancellationSignal,
+ @CallbackExecutor @NonNull Executor executor,
+ @NonNull
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>
+ callback) {
+ requireNonNull(executor, "executor must not be null");
+ requireNonNull(callback, "callback must not be null");
+
+ if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+ Log.w(TAG, "listEnabledProviders already canceled");
+ return;
+ }
+
+ ICancellationSignal cancelRemote = null;
+ try {
+ cancelRemote =
+ mService.listEnabledProviders(
+ new ListEnabledProvidersTransport(executor, callback));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+
+ if (cancellationSignal != null && cancelRemote != null) {
+ cancellationSignal.setRemote(cancelRemote);
+ }
+ }
+
+ /**
+ * Sets a list of all user configurable credential providers registered on the system. This API
+ * is intended for settings apps.
+ *
+ * @param providers the list of enabled providers
+ * @param userId the user ID to configure credential manager for
+ * @param executor the callback will take place on this {@link Executor}
+ * @param callback the callback invoked when the request succeeds or fails
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public void setEnabledProviders(
+ @NonNull List<String> providers,
+ int userId,
+ @CallbackExecutor @NonNull Executor executor,
+ @NonNull OutcomeReceiver<Void, SetEnabledProvidersException> callback) {
+ requireNonNull(executor, "executor must not be null");
+ requireNonNull(callback, "callback must not be null");
+ requireNonNull(providers, "providers must not be null");
+
+ try {
+ mService.setEnabledProviders(
+ providers, userId, new SetEnabledProvidersTransport(executor, callback));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
private static class GetCredentialTransport extends IGetCredentialCallback.Stub {
// TODO: listen for cancellation to release callback.
private final Activity mActivity;
private final Executor mExecutor;
- private final OutcomeReceiver<
- GetCredentialResponse, GetCredentialException> mCallback;
+ private final OutcomeReceiver<GetCredentialResponse, GetCredentialException> mCallback;
- private GetCredentialTransport(Activity activity, Executor executor,
+ private GetCredentialTransport(
+ Activity activity,
+ Executor executor,
OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
mActivity = activity;
mExecutor = executor;
@@ -210,8 +287,10 @@ public final class CredentialManager {
try {
mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "startIntentSender() failed for intent:"
- + pendingIntent.getIntentSender(), e);
+ Log.e(
+ TAG,
+ "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(),
+ e);
// TODO: propagate the error.
}
}
@@ -233,10 +312,12 @@ public final class CredentialManager {
private final Activity mActivity;
private final Executor mExecutor;
- private final OutcomeReceiver<
- CreateCredentialResponse, CreateCredentialException> mCallback;
+ private final OutcomeReceiver<CreateCredentialResponse, CreateCredentialException>
+ mCallback;
- private CreateCredentialTransport(Activity activity, Executor executor,
+ private CreateCredentialTransport(
+ Activity activity,
+ Executor executor,
OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback) {
mActivity = activity;
mExecutor = executor;
@@ -248,8 +329,10 @@ public final class CredentialManager {
try {
mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "startIntentSender() failed for intent:"
- + pendingIntent.getIntentSender(), e);
+ Log.e(
+ TAG,
+ "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(),
+ e);
// TODO: propagate the error.
}
}
@@ -266,15 +349,14 @@ public final class CredentialManager {
}
}
- private static class ClearCredentialStateTransport
- extends IClearCredentialStateCallback.Stub {
+ private static class ClearCredentialStateTransport extends IClearCredentialStateCallback.Stub {
// TODO: listen for cancellation to release callback.
private final Executor mExecutor;
private final OutcomeReceiver<Void, ClearCredentialStateException> mCallback;
- private ClearCredentialStateTransport(Executor executor,
- OutcomeReceiver<Void, ClearCredentialStateException> callback) {
+ private ClearCredentialStateTransport(
+ Executor executor, OutcomeReceiver<Void, ClearCredentialStateException> callback) {
mExecutor = executor;
mCallback = callback;
}
@@ -290,4 +372,59 @@ public final class CredentialManager {
() -> mCallback.onError(new ClearCredentialStateException(errorType, message)));
}
}
+
+ private static class ListEnabledProvidersTransport extends IListEnabledProvidersCallback.Stub {
+ // TODO: listen for cancellation to release callback.
+
+ private final Executor mExecutor;
+ private final OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>
+ mCallback;
+
+ private ListEnabledProvidersTransport(
+ Executor executor,
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>
+ callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResponse(ListEnabledProvidersResponse response) {
+ mExecutor.execute(() -> mCallback.onResult(response));
+ }
+
+ @Override
+ public void onError(String errorType, String message) {
+ mExecutor.execute(
+ () -> mCallback.onError(new ListEnabledProvidersException(errorType, message)));
+ }
+ }
+
+ private static class SetEnabledProvidersTransport extends ISetEnabledProvidersCallback.Stub {
+ // TODO: listen for cancellation to release callback.
+
+ private final Executor mExecutor;
+ private final OutcomeReceiver<Void, SetEnabledProvidersException> mCallback;
+
+ private SetEnabledProvidersTransport(
+ Executor executor, OutcomeReceiver<Void, SetEnabledProvidersException> callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ public void onResponse(Void result) {
+ mExecutor.execute(() -> mCallback.onResult(result));
+ }
+
+ @Override
+ public void onResponse() {
+ mExecutor.execute(() -> mCallback.onResult(null));
+ }
+
+ @Override
+ public void onError(String errorType, String message) {
+ mExecutor.execute(
+ () -> mCallback.onError(new SetEnabledProvidersException(errorType, message)));
+ }
+ }
}
diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl
index c5497bdbdc0f..c3ca03dcdfd2 100644
--- a/core/java/android/credentials/ICredentialManager.aidl
+++ b/core/java/android/credentials/ICredentialManager.aidl
@@ -16,12 +16,16 @@
package android.credentials;
+import java.util.List;
+
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest;
import android.credentials.IClearCredentialStateCallback;
import android.credentials.ICreateCredentialCallback;
import android.credentials.IGetCredentialCallback;
+import android.credentials.IListEnabledProvidersCallback;
+import android.credentials.ISetEnabledProvidersCallback;
import android.os.ICancellationSignal;
/**
@@ -36,4 +40,8 @@ interface ICredentialManager {
@nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage);
@nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage);
+
+ @nullable ICancellationSignal listEnabledProviders(in IListEnabledProvidersCallback callback);
+
+ void setEnabledProviders(in List<String> providers, in int userId, in ISetEnabledProvidersCallback callback);
}
diff --git a/core/java/android/credentials/IListEnabledProvidersCallback.aidl b/core/java/android/credentials/IListEnabledProvidersCallback.aidl
new file mode 100644
index 000000000000..3a8e25ed954a
--- /dev/null
+++ b/core/java/android/credentials/IListEnabledProvidersCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.credentials.ListEnabledProvidersResponse;
+
+/**
+ * Listener for an listEnabledProviders request.
+ *
+ * @hide
+ */
+interface IListEnabledProvidersCallback {
+ oneway void onResponse(in ListEnabledProvidersResponse response);
+ oneway void onError(String errorType, String message);
+} \ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/external/RoSystemProperties.kt b/core/java/android/credentials/ISetEnabledProvidersCallback.aidl
index 528680e77879..30442786d11f 100644
--- a/services/permission/java/com/android/server/permission/access/external/RoSystemProperties.kt
+++ b/core/java/android/credentials/ISetEnabledProvidersCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright 2022 The Android Open 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,11 +14,14 @@
* limitations under the License.
*/
-package com.android.server.permission.access.external
+package android.credentials;
-class RoSystemProperties {
- companion object {
- const val CONTROL_PRIVAPP_PERMISSIONS_DISABLE = false
- const val CONTROL_PRIVAPP_PERMISSIONS_ENFORCE = false
- }
-}
+/**
+ * Listener for an setEnabledProviders request.
+ *
+ * @hide
+ */
+interface ISetEnabledProvidersCallback {
+ oneway void onResponse();
+ oneway void onError(String errorType, String message);
+} \ No newline at end of file
diff --git a/core/java/android/credentials/ListEnabledProvidersException.java b/core/java/android/credentials/ListEnabledProvidersException.java
new file mode 100644
index 000000000000..c12c65672664
--- /dev/null
+++ b/core/java/android/credentials/ListEnabledProvidersException.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.CancellationSignal;
+import android.os.OutcomeReceiver;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents an error encountered during the {@link
+ * CredentialManager#listEnabledProviders(CancellationSignal Executor, OutcomeReceiver)} operation.
+ *
+ * @hide
+ */
+public class ListEnabledProvidersException extends Exception {
+
+ @NonNull public final String errorType;
+
+ /**
+ * Constructs a {@link ListEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public ListEnabledProvidersException(@NonNull String errorType, @Nullable String message) {
+ this(errorType, message, null);
+ }
+
+ /**
+ * Constructs a {@link ListEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public ListEnabledProvidersException(
+ @NonNull String errorType, @Nullable String message, @Nullable Throwable cause) {
+ super(message, cause);
+ this.errorType =
+ Preconditions.checkStringNotEmpty(errorType, "errorType must not be empty");
+ }
+
+ /**
+ * Constructs a {@link ListEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public ListEnabledProvidersException(@NonNull String errorType, @Nullable Throwable cause) {
+ this(errorType, null, cause);
+ }
+
+ /**
+ * Constructs a {@link ListEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public ListEnabledProvidersException(@NonNull String errorType) {
+ this(errorType, null, null);
+ }
+}
diff --git a/services/permission/java/com/android/server/permission/access/external/UserHandle.kt b/core/java/android/credentials/ListEnabledProvidersResponse.aidl
index e1072a760dc2..759bf48bf57a 100644
--- a/services/permission/java/com/android/server/permission/access/external/UserHandle.kt
+++ b/core/java/android/credentials/ListEnabledProvidersResponse.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2022 The Android Open 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,18 +14,6 @@
* limitations under the License.
*/
-package com.android.server.permission.access.external
+package android.credentials;
-interface UserHandle {
- companion object {
- fun getAppId(uid: Int): Int {
- throw NotImplementedError()
- }
- }
-}
-
-object UserHandleCompat {
- fun getUserId(uid: Int): Int {
- throw NotImplementedError()
- }
-}
+parcelable ListEnabledProvidersResponse; \ No newline at end of file
diff --git a/core/java/android/credentials/ListEnabledProvidersResponse.java b/core/java/android/credentials/ListEnabledProvidersResponse.java
new file mode 100644
index 000000000000..532adf7f0c50
--- /dev/null
+++ b/core/java/android/credentials/ListEnabledProvidersResponse.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Response from Credential Manager listing the providers that are enabled and available to the
+ * user.
+ *
+ * @hide
+ */
+public final class ListEnabledProvidersResponse implements Parcelable {
+
+ /** List of providers. */
+ @NonNull private final List<String> mProviders;
+
+ /**
+ * Creates a {@link ListEnabledProvidersResponse} with a list of providers.
+ *
+ * @throws NullPointerException If args are null.
+ */
+ public static @NonNull ListEnabledProvidersResponse create(@NonNull List<String> providers) {
+ Objects.requireNonNull(providers, "providers must not be null");
+ Preconditions.checkCollectionElementsNotNull(providers, /* valueName= */ "providers");
+ return new ListEnabledProvidersResponse(providers);
+ }
+
+ private ListEnabledProvidersResponse(@NonNull List<String> providers) {
+ mProviders = providers;
+ }
+
+ private ListEnabledProvidersResponse(@NonNull Parcel in) {
+ mProviders = in.createStringArrayList();
+ }
+
+ public static final @NonNull Creator<ListEnabledProvidersResponse> CREATOR =
+ new Creator<ListEnabledProvidersResponse>() {
+ @Override
+ public ListEnabledProvidersResponse createFromParcel(Parcel in) {
+ return new ListEnabledProvidersResponse(in);
+ }
+
+ @Override
+ public ListEnabledProvidersResponse[] newArray(int size) {
+ return new ListEnabledProvidersResponse[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStringList(mProviders);
+ }
+
+ /** Returns the list of flattened Credential Manager provider component names as strings. */
+ public @NonNull List<String> getProviderComponentNames() {
+ return mProviders;
+ }
+}
diff --git a/core/java/android/credentials/SetEnabledProvidersException.java b/core/java/android/credentials/SetEnabledProvidersException.java
new file mode 100644
index 000000000000..6178f349e736
--- /dev/null
+++ b/core/java/android/credentials/SetEnabledProvidersException.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.CancellationSignal;
+import android.os.OutcomeReceiver;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents an error encountered during the {@link
+ * CredentialManager#setEnabledProviders(CancellationSignal Executor, OutcomeReceiver)} operation.
+ *
+ * @hide
+ */
+public class SetEnabledProvidersException extends Exception {
+
+ @NonNull public final String errorType;
+
+ /**
+ * Constructs a {@link SetEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public SetEnabledProvidersException(@NonNull String errorType, @Nullable String message) {
+ this(errorType, message, null);
+ }
+
+ /**
+ * Constructs a {@link SetEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public SetEnabledProvidersException(
+ @NonNull String errorType, @Nullable String message, @Nullable Throwable cause) {
+ super(message, cause);
+ this.errorType =
+ Preconditions.checkStringNotEmpty(errorType, "errorType must not be empty");
+ }
+
+ /**
+ * Constructs a {@link SetEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public SetEnabledProvidersException(@NonNull String errorType, @Nullable Throwable cause) {
+ this(errorType, null, cause);
+ }
+
+ /**
+ * Constructs a {@link SetEnabledProvidersException}.
+ *
+ * @throws IllegalArgumentException If errorType is empty.
+ */
+ public SetEnabledProvidersException(@NonNull String errorType) {
+ this(errorType, null, null);
+ }
+}
diff --git a/core/java/android/credentials/SetEnabledProvidersRequest.aidl b/core/java/android/credentials/SetEnabledProvidersRequest.aidl
new file mode 100644
index 000000000000..271f58fda532
--- /dev/null
+++ b/core/java/android/credentials/SetEnabledProvidersRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+parcelable SetEnabledProvidersRequest; \ No newline at end of file
diff --git a/core/java/android/credentials/SetEnabledProvidersRequest.java b/core/java/android/credentials/SetEnabledProvidersRequest.java
new file mode 100644
index 000000000000..d1136ba00421
--- /dev/null
+++ b/core/java/android/credentials/SetEnabledProvidersRequest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Sets the enabled list of credential manager providers.
+ *
+ * @hide
+ */
+public final class SetEnabledProvidersRequest implements Parcelable {
+
+ /** List of providers. */
+ @NonNull private final List<String> mProviders;
+
+ /**
+ * Creates a {@link SetEnabledProvidersRequest} with a list of providers. The list is made up of
+ * strings that are flattened component names of the service that is the credman provider.
+ *
+ * @throws NullPointerException If args are null.
+ */
+ public SetEnabledProvidersRequest(@NonNull List<String> providers) {
+ Objects.requireNonNull(providers, "providers must not be null");
+ Preconditions.checkCollectionElementsNotNull(providers, /* valueName= */ "providers");
+ mProviders = providers;
+ }
+
+ private SetEnabledProvidersRequest(@NonNull Parcel in) {
+ mProviders = in.createStringArrayList();
+ }
+
+ public static final @NonNull Creator<SetEnabledProvidersRequest> CREATOR =
+ new Creator<SetEnabledProvidersRequest>() {
+ @Override
+ public SetEnabledProvidersRequest createFromParcel(Parcel in) {
+ return new SetEnabledProvidersRequest(in);
+ }
+
+ @Override
+ public SetEnabledProvidersRequest[] newArray(int size) {
+ return new SetEnabledProvidersRequest[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStringList(mProviders);
+ }
+
+ /** Returns the list of flattened Credential Manager provider component names as strings. */
+ public @NonNull List<String> getProviderComponentNames() {
+ return mProviders;
+ }
+}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 3bdd39f5d7d7..5291d2b73891 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -29,12 +29,14 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.ActivityThread;
import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraManager;
import android.media.AudioAttributes;
import android.media.IAudioService;
import android.os.Build;
@@ -45,6 +47,7 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RSIllegalArgumentException;
@@ -281,6 +284,14 @@ public class Camera {
*/
public native static int getNumberOfCameras();
+ private static final boolean sLandscapeToPortrait =
+ SystemProperties.getBoolean(CameraManager.LANDSCAPE_TO_PORTRAIT_PROP, false);
+
+ private static boolean shouldOverrideToPortrait() {
+ return CompatChanges.isChangeEnabled(CameraManager.OVERRIDE_FRONT_CAMERA_APP_COMPAT)
+ && sLandscapeToPortrait;
+ }
+
/**
* Returns the information about a particular camera.
* If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1.
@@ -290,7 +301,9 @@ public class Camera {
* low-level failure).
*/
public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
- _getCameraInfo(cameraId, cameraInfo);
+ boolean overrideToPortrait = shouldOverrideToPortrait();
+
+ _getCameraInfo(cameraId, overrideToPortrait, cameraInfo);
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
IAudioService audioService = IAudioService.Stub.asInterface(b);
try {
@@ -303,7 +316,8 @@ public class Camera {
Log.e(TAG, "Audio service is unavailable for queries");
}
}
- private native static void _getCameraInfo(int cameraId, CameraInfo cameraInfo);
+ private native static void _getCameraInfo(int cameraId, boolean overrideToPortrait,
+ CameraInfo cameraInfo);
/**
* Information about a camera
@@ -484,8 +498,9 @@ public class Camera {
mEventHandler = null;
}
+ boolean overrideToPortrait = shouldOverrideToPortrait();
return native_setup(new WeakReference<Camera>(this), cameraId,
- ActivityThread.currentOpPackageName());
+ ActivityThread.currentOpPackageName(), overrideToPortrait);
}
/** used by Camera#open, Camera#open(int) */
@@ -555,7 +570,8 @@ public class Camera {
}
@UnsupportedAppUsage
- private native int native_setup(Object cameraThis, int cameraId, String packageName);
+ private native int native_setup(Object cameraThis, int cameraId, String packageName,
+ boolean overrideToPortrait);
private native final void native_release();
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 161b1b71121e..9388ae3fd5e4 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -17,7 +17,7 @@
package android.hardware;
import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED;
-import static android.companion.virtual.VirtualDeviceManager.DEFAULT_DEVICE_ID;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
@@ -530,7 +530,7 @@ public class SystemSensorManager extends SensorManager {
if (intent.getAction().equals(ACTION_VIRTUAL_DEVICE_REMOVED)) {
synchronized (mFullRuntimeSensorListByDevice) {
final int deviceId = intent.getIntExtra(
- EXTRA_VIRTUAL_DEVICE_ID, DEFAULT_DEVICE_ID);
+ EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT);
List<Sensor> removedSensors =
mFullRuntimeSensorListByDevice.removeReturnOld(deviceId);
if (removedSensors != null) {
@@ -1134,7 +1134,7 @@ public class SystemSensorManager extends SensorManager {
}
private boolean isDeviceSensorPolicyDefault(int deviceId) {
- if (deviceId == DEFAULT_DEVICE_ID) {
+ if (deviceId == DEVICE_ID_DEFAULT) {
return true;
}
if (mVdm == null) {
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index f858227a0f1d..ce191e83619f 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -23,6 +23,10 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
@@ -104,6 +108,24 @@ public final class CameraManager {
private final boolean mHasOpenCloseListenerPermission;
/**
+ * Force camera output to be rotated to portrait orientation on landscape cameras.
+ * Many apps do not handle this situation and display stretched images otherwise.
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU)
+ @TestApi
+ public static final long OVERRIDE_FRONT_CAMERA_APP_COMPAT = 250678880L;
+
+ /**
+ * System property for allowing the above
+ * @hide
+ */
+ public static final String LANDSCAPE_TO_PORTRAIT_PROP =
+ "camera.enable_landscape_to_portrait";
+
+ /**
* @hide
*/
public CameraManager(Context context) {
@@ -526,7 +548,8 @@ public final class CameraManager {
for (String physicalCameraId : physicalCameraIds) {
CameraMetadataNative physicalCameraInfo =
cameraService.getCameraCharacteristics(physicalCameraId,
- mContext.getApplicationInfo().targetSdkVersion);
+ mContext.getApplicationInfo().targetSdkVersion,
+ /*overrideToPortrait*/false);
StreamConfiguration[] configs = physicalCameraInfo.get(
CameraCharacteristics.
SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS);
@@ -585,8 +608,9 @@ public final class CameraManager {
try {
Size displaySize = getDisplaySize();
+ boolean overrideToPortrait = shouldOverrideToPortrait();
CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId,
- mContext.getApplicationInfo().targetSdkVersion);
+ mContext.getApplicationInfo().targetSdkVersion, overrideToPortrait);
try {
info.setCameraId(Integer.parseInt(cameraId));
} catch (NumberFormatException e) {
@@ -703,9 +727,12 @@ public final class CameraManager {
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
}
+
+ boolean overrideToPortrait = shouldOverrideToPortrait();
cameraUser = cameraService.connectDevice(callbacks, cameraId,
- mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
- oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion);
+ mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
+ oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion,
+ overrideToPortrait);
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
@@ -1133,6 +1160,11 @@ public final class CameraManager {
return CameraManagerGlobal.get().getTorchStrengthLevel(cameraId);
}
+ private static boolean shouldOverrideToPortrait() {
+ return CompatChanges.isChangeEnabled(OVERRIDE_FRONT_CAMERA_APP_COMPAT)
+ && CameraManagerGlobal.sLandscapeToPortrait;
+ }
+
/**
* A callback for camera devices becoming available or unavailable to open.
*
@@ -1579,6 +1611,9 @@ public final class CameraManager {
public static final boolean sCameraServiceDisabled =
SystemProperties.getBoolean("config.disable_cameraservice", false);
+ public static final boolean sLandscapeToPortrait =
+ SystemProperties.getBoolean(LANDSCAPE_TO_PORTRAIT_PROP, false);
+
public static CameraManagerGlobal get() {
return gCameraManager;
}
diff --git a/core/java/android/hardware/display/AmbientBrightnessDayStats.java b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
index 8aff911ea42c..28167065ecc4 100644
--- a/core/java/android/hardware/display/AmbientBrightnessDayStats.java
+++ b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
@@ -208,7 +208,7 @@ public final class AmbientBrightnessDayStats implements Parcelable {
}
private int getBucketIndex(float ambientBrightness) {
- if (ambientBrightness < mBucketBoundaries[0]) {
+ if (ambientBrightness < mBucketBoundaries[0] || Float.isNaN(ambientBrightness)) {
return -1;
}
int low = 0;
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index eef0f421d29f..6314cabd298d 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -120,8 +120,8 @@ interface IInputManager {
in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
String keyboardLayoutDescriptor);
- String[] getKeyboardLayoutListForInputDevice(in InputDeviceIdentifier identifier, int userId,
- in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
+ KeyboardLayout[] getKeyboardLayoutListForInputDevice(in InputDeviceIdentifier identifier,
+ int userId, in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
// Modifier key remapping APIs.
@EnforcePermission("REMAP_MODIFIER_KEYS")
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index a616014b1b84..2eeae46645c5 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -986,7 +986,7 @@ public final class InputManager {
@Nullable
public String getKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype) {
+ @Nullable InputMethodSubtype imeSubtype) {
try {
return mIm.getKeyboardLayoutForInputDevice(identifier, userId, imeInfo, imeSubtype);
} catch (RemoteException ex) {
@@ -1014,7 +1014,7 @@ public final class InputManager {
@RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
public void setKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype, @NonNull String keyboardLayoutDescriptor) {
+ @Nullable InputMethodSubtype imeSubtype, @NonNull String keyboardLayoutDescriptor) {
if (identifier == null) {
throw new IllegalArgumentException("identifier must not be null");
}
@@ -1031,8 +1031,8 @@ public final class InputManager {
}
/**
- * Gets all keyboard layout descriptors that are enabled for the specified input device, userId,
- * imeInfo and imeSubtype.
+ * Gets all keyboard layouts that are enabled for the specified input device, userId, imeInfo
+ * and imeSubtype.
*
* @param identifier The identifier for the input device.
* @param userId user profile ID
@@ -1042,9 +1042,9 @@ public final class InputManager {
*
* @hide
*/
- public String[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
+ public KeyboardLayout[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype) {
+ @Nullable InputMethodSubtype imeSubtype) {
if (identifier == null) {
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index fd3fe3731b74..dcf002613b80 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -15,16 +15,23 @@
*/
package android.net.vcn;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import static com.android.internal.annotations.VisibleForTesting.Visibility;
+import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
+import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -32,6 +39,7 @@ import com.android.server.vcn.util.PersistableBundleUtils;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
@@ -46,22 +54,36 @@ import java.util.Set;
public final class VcnConfig implements Parcelable {
@NonNull private static final String TAG = VcnConfig.class.getSimpleName();
+ private static final Set<Integer> ALLOWED_TRANSPORTS = new ArraySet<>();
+
+ static {
+ ALLOWED_TRANSPORTS.add(TRANSPORT_WIFI);
+ ALLOWED_TRANSPORTS.add(TRANSPORT_CELLULAR);
+ }
+
private static final String PACKAGE_NAME_KEY = "mPackageName";
@NonNull private final String mPackageName;
private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs";
@NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs;
+ private static final Set<Integer> RESTRICTED_TRANSPORTS_DEFAULT =
+ Collections.singleton(TRANSPORT_WIFI);
+ private static final String RESTRICTED_TRANSPORTS_KEY = "mRestrictedTransports";
+ @NonNull private final Set<Integer> mRestrictedTransports;
+
private static final String IS_TEST_MODE_PROFILE_KEY = "mIsTestModeProfile";
private final boolean mIsTestModeProfile;
private VcnConfig(
@NonNull String packageName,
@NonNull Set<VcnGatewayConnectionConfig> gatewayConnectionConfigs,
+ @NonNull Set<Integer> restrictedTransports,
boolean isTestModeProfile) {
mPackageName = packageName;
mGatewayConnectionConfigs =
Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs));
+ mRestrictedTransports = Collections.unmodifiableSet(new ArraySet<>(restrictedTransports));
mIsTestModeProfile = isTestModeProfile;
validate();
@@ -82,6 +104,20 @@ public final class VcnConfig implements Parcelable {
new ArraySet<>(
PersistableBundleUtils.toList(
gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new));
+
+ final PersistableBundle restrictedTransportsBundle =
+ in.getPersistableBundle(RESTRICTED_TRANSPORTS_KEY);
+ if (restrictedTransportsBundle == null) {
+ // RESTRICTED_TRANSPORTS_KEY was added in U and does not exist in VcnConfigs created in
+ // older platforms
+ mRestrictedTransports = RESTRICTED_TRANSPORTS_DEFAULT;
+ } else {
+ mRestrictedTransports =
+ new ArraySet<Integer>(
+ PersistableBundleUtils.toList(
+ restrictedTransportsBundle, INTEGER_DESERIALIZER));
+ }
+
mIsTestModeProfile = in.getBoolean(IS_TEST_MODE_PROFILE_KEY);
validate();
@@ -91,6 +127,19 @@ public final class VcnConfig implements Parcelable {
Objects.requireNonNull(mPackageName, "packageName was null");
Preconditions.checkCollectionNotEmpty(
mGatewayConnectionConfigs, "gatewayConnectionConfigs was empty");
+
+ final Iterator<Integer> iterator = mRestrictedTransports.iterator();
+ while (iterator.hasNext()) {
+ final int transport = iterator.next();
+ if (!ALLOWED_TRANSPORTS.contains(transport)) {
+ iterator.remove();
+ Log.w(
+ TAG,
+ "Found invalid transport "
+ + transport
+ + " which might be from a new version of VcnConfig");
+ }
+ }
}
/**
@@ -110,6 +159,16 @@ public final class VcnConfig implements Parcelable {
}
/**
+ * Retrieve the transports that will be restricted by the VCN.
+ *
+ * @see Builder#setRestrictedUnderlyingNetworkTransports(Set)
+ */
+ @NonNull
+ public Set<Integer> getRestrictedUnderlyingNetworkTransports() {
+ return Collections.unmodifiableSet(mRestrictedTransports);
+ }
+
+ /**
* Returns whether or not this VcnConfig is restricted to test networks.
*
* @hide
@@ -134,6 +193,12 @@ public final class VcnConfig implements Parcelable {
new ArrayList<>(mGatewayConnectionConfigs),
VcnGatewayConnectionConfig::toPersistableBundle);
result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle);
+
+ final PersistableBundle restrictedTransportsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mRestrictedTransports), INTEGER_SERIALIZER);
+ result.putPersistableBundle(RESTRICTED_TRANSPORTS_KEY, restrictedTransportsBundle);
+
result.putBoolean(IS_TEST_MODE_PROFILE_KEY, mIsTestModeProfile);
return result;
@@ -141,7 +206,8 @@ public final class VcnConfig implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile);
+ return Objects.hash(
+ mPackageName, mGatewayConnectionConfigs, mRestrictedTransports, mIsTestModeProfile);
}
@Override
@@ -153,6 +219,7 @@ public final class VcnConfig implements Parcelable {
final VcnConfig rhs = (VcnConfig) other;
return mPackageName.equals(rhs.mPackageName)
&& mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs)
+ && mRestrictedTransports.equals(rhs.mRestrictedTransports)
&& mIsTestModeProfile == rhs.mIsTestModeProfile;
}
@@ -189,12 +256,15 @@ public final class VcnConfig implements Parcelable {
@NonNull
private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs = new ArraySet<>();
+ @NonNull private final Set<Integer> mRestrictedTransports = new ArraySet<>();
+
private boolean mIsTestModeProfile = false;
public Builder(@NonNull Context context) {
Objects.requireNonNull(context, "context was null");
mPackageName = context.getOpPackageName();
+ mRestrictedTransports.addAll(RESTRICTED_TRANSPORTS_DEFAULT);
}
/**
@@ -225,6 +295,36 @@ public final class VcnConfig implements Parcelable {
return this;
}
+ private void validateRestrictedTransportsOrThrow(Set<Integer> restrictedTransports) {
+ Objects.requireNonNull(restrictedTransports, "transports was null");
+
+ for (int transport : restrictedTransports) {
+ if (!ALLOWED_TRANSPORTS.contains(transport)) {
+ throw new IllegalArgumentException("Invalid transport " + transport);
+ }
+ }
+ }
+
+ /**
+ * Sets transports that will be restricted by the VCN.
+ *
+ * @param transports transports that will be restricted by VCN. Networks that include any
+ * of the transports will be marked as restricted. Only {@link
+ * NetworkCapabilities#TRANSPORT_WIFI} and {@link
+ * NetworkCapabilities#TRANSPORT_CELLULAR} are allowed. {@link
+ * NetworkCapabilities#TRANSPORT_WIFI} is marked restricted by default.
+ * @return this {@link Builder} instance, for chaining
+ * @throws IllegalArgumentException if the input contains unsupported transport types.
+ */
+ @NonNull
+ public Builder setRestrictedUnderlyingNetworkTransports(@NonNull Set<Integer> transports) {
+ validateRestrictedTransportsOrThrow(transports);
+
+ mRestrictedTransports.clear();
+ mRestrictedTransports.addAll(transports);
+ return this;
+ }
+
/**
* Restricts this VcnConfig to matching with test networks (only).
*
@@ -248,7 +348,11 @@ public final class VcnConfig implements Parcelable {
*/
@NonNull
public VcnConfig build() {
- return new VcnConfig(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile);
+ return new VcnConfig(
+ mPackageName,
+ mGatewayConnectionConfigs,
+ mRestrictedTransports,
+ mIsTestModeProfile);
}
}
}
diff --git a/core/java/android/os/CoolingDevice.java b/core/java/android/os/CoolingDevice.java
index 4babd4b524c9..4ddcd9d4ff8b 100644
--- a/core/java/android/os/CoolingDevice.java
+++ b/core/java/android/os/CoolingDevice.java
@@ -19,7 +19,7 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.thermal.V2_0.CoolingType;
+import android.hardware.thermal.CoolingType;
import com.android.internal.util.Preconditions;
@@ -52,11 +52,16 @@ public final class CoolingDevice implements Parcelable {
TYPE_MODEM,
TYPE_NPU,
TYPE_COMPONENT,
+ TYPE_TPU,
+ TYPE_POWER_AMPLIFIER,
+ TYPE_DISPLAY,
+ TYPE_SPEAKER
})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
- /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+ /** Keep in sync with hardware/interfaces/thermal/aidl/android/hardware/thermal
+ * /ThrottlingSeverity.aidl */
/** Fan for active cooling */
public static final int TYPE_FAN = CoolingType.FAN;
/** Battery charging cooling deivice */
@@ -67,10 +72,18 @@ public final class CoolingDevice implements Parcelable {
public static final int TYPE_GPU = CoolingType.GPU;
/** Modem cooling deivice */
public static final int TYPE_MODEM = CoolingType.MODEM;
- /** NPU/TPU cooling deivice */
+ /** NPU cooling deivice */
public static final int TYPE_NPU = CoolingType.NPU;
/** Generic passive cooling deivice */
public static final int TYPE_COMPONENT = CoolingType.COMPONENT;
+ /** TPU cooling deivice */
+ public static final int TYPE_TPU = CoolingType.TPU;
+ /** Power amplifier cooling device */
+ public static final int TYPE_POWER_AMPLIFIER = CoolingType.POWER_AMPLIFIER;
+ /** Display cooling device */
+ public static final int TYPE_DISPLAY = CoolingType.DISPLAY;
+ /** Speaker cooling device */
+ public static final int TYPE_SPEAKER = CoolingType.SPEAKER;
/**
* Verify a valid cooling device type.
@@ -78,7 +91,7 @@ public final class CoolingDevice implements Parcelable {
* @return true if a cooling device type is valid otherwise false.
*/
public static boolean isValidType(@Type int type) {
- return type >= TYPE_FAN && type <= TYPE_COMPONENT;
+ return type >= TYPE_FAN && type <= TYPE_SPEAKER;
}
public CoolingDevice(long value, @Type int type, @NonNull String name) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 399f11b0f2a7..a31c2e6693b6 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1956,7 +1956,21 @@ public final class Debug
/** @hide */
public static final int MEMINFO_UNEVICTABLE = 18;
/** @hide */
- public static final int MEMINFO_COUNT = 19;
+ public static final int MEMINFO_AVAILABLE = 19;
+ /** @hide */
+ public static final int MEMINFO_ACTIVE_ANON = 20;
+ /** @hide */
+ public static final int MEMINFO_INACTIVE_ANON = 21;
+ /** @hide */
+ public static final int MEMINFO_ACTIVE_FILE = 22;
+ /** @hide */
+ public static final int MEMINFO_INACTIVE_FILE = 23;
+ /** @hide */
+ public static final int MEMINFO_CMA_TOTAL = 24;
+ /** @hide */
+ public static final int MEMINFO_CMA_FREE = 25;
+ /** @hide */
+ public static final int MEMINFO_COUNT = 26;
/**
* Retrieves /proc/meminfo. outSizes is filled with fields
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ffa9507ebc2a..536ef31f334a 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -18,6 +18,7 @@ package android.os;
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -44,6 +45,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
+import java.util.UUID;
/**
* Provides access to environment variables.
@@ -551,12 +553,37 @@ public class Environment {
}
/** {@hide} */
- public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
- String packageName) {
+ @NonNull
+ public static File getDataUserCePackageDirectory(@Nullable String volumeUuid, int userId,
+ @NonNull String packageName) {
// TODO: keep consistent with installd
return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
}
+ /**
+ * Retrieve the credential encrypted data directory for a specific package of a specific user.
+ * This is equivalent to {@link ApplicationInfo#credentialProtectedDataDir}, exposed because
+ * fetching a full {@link ApplicationInfo} instance may be expensive if all the caller needs
+ * is this directory.
+ *
+ * @param storageUuid The storage volume for this directory, usually retrieved from a
+ * {@link StorageManager} API or {@link ApplicationInfo#storageUuid}.
+ * @param user The user this directory is for.
+ * @param packageName The app this directory is for.
+ *
+ * @see ApplicationInfo#credentialProtectedDataDir
+ * @return A file to the directory.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public static File getDataCePackageDirectoryForUser(@NonNull UUID storageUuid,
+ @NonNull UserHandle user, @NonNull String packageName) {
+ var volumeUuid = StorageManager.convert(storageUuid);
+ return getDataUserCePackageDirectory(volumeUuid, user.getIdentifier(), packageName);
+ }
+
/** {@hide} */
public static File getDataUserDeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), DIR_USER_DE);
@@ -568,13 +595,38 @@ public class Environment {
}
/** {@hide} */
- public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
- String packageName) {
+ @NonNull
+ public static File getDataUserDePackageDirectory(@Nullable String volumeUuid, int userId,
+ @NonNull String packageName) {
// TODO: keep consistent with installd
return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
}
/**
+ * Retrieve the device encrypted data directory for a specific package of a specific user. This
+ * is equivalent to {@link ApplicationInfo#deviceProtectedDataDir}, exposed because fetching a
+ * full {@link ApplicationInfo} instance may be expensive if all the caller needs is this
+ * directory.
+ *
+ * @param storageUuid The storage volume for this directory, usually retrieved from a
+ * {@link StorageManager} API or {@link ApplicationInfo#storageUuid}.
+ * @param user The user this directory is for.
+ * @param packageName The app this directory is for.
+ *
+ * @see ApplicationInfo#deviceProtectedDataDir
+ * @return A file to the directory.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public static File getDataDePackageDirectoryForUser(@NonNull UUID storageUuid,
+ @NonNull UserHandle user, @NonNull String packageName) {
+ var volumeUuid = StorageManager.convert(storageUuid);
+ return getDataUserDePackageDirectory(volumeUuid, user.getIdentifier(), packageName);
+ }
+
+ /**
* Return preloads directory.
* <p>This directory may contain pre-loaded content such as
* {@link #getDataPreloadsDemoDirectory() demo videos} and
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index 3a5666283ae2..cc5426631a7b 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -84,6 +84,15 @@
"include-filter": "android.os.cts.SharedMemoryTest"
}
]
+ },
+ {
+ "file_patterns": ["Environment[^/]*\\.java"],
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.os.EnvironmentTest"
+ }
+ ]
}
],
"postsubmit": [
diff --git a/core/java/android/os/Temperature.java b/core/java/android/os/Temperature.java
index 55785f3bdba9..a138431f745a 100644
--- a/core/java/android/os/Temperature.java
+++ b/core/java/android/os/Temperature.java
@@ -19,8 +19,8 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.thermal.V2_0.TemperatureType;
-import android.hardware.thermal.V2_0.ThrottlingSeverity;
+import android.hardware.thermal.TemperatureType;
+import android.hardware.thermal.ThrottlingSeverity;
import com.android.internal.util.Preconditions;
@@ -54,7 +54,8 @@ public final class Temperature implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface ThrottlingStatus {}
- /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+ /** Keep in sync with hardware/interfaces/thermal/aidl/android/hardware/thermal
+ * /ThrottlingSeverity.aidl */
public static final int THROTTLING_NONE = ThrottlingSeverity.NONE;
public static final int THROTTLING_LIGHT = ThrottlingSeverity.LIGHT;
public static final int THROTTLING_MODERATE = ThrottlingSeverity.MODERATE;
@@ -75,11 +76,16 @@ public final class Temperature implements Parcelable {
TYPE_BCL_CURRENT,
TYPE_BCL_PERCENTAGE,
TYPE_NPU,
+ TYPE_TPU,
+ TYPE_DISPLAY,
+ TYPE_MODEM,
+ TYPE_SOC
})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
- /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+ /** Keep in sync with hardware/interfaces/thermal/aidl/android/hardware/thermal
+ * /TemperatureType.aidl */
public static final int TYPE_UNKNOWN = TemperatureType.UNKNOWN;
public static final int TYPE_CPU = TemperatureType.CPU;
public static final int TYPE_GPU = TemperatureType.GPU;
@@ -91,6 +97,10 @@ public final class Temperature implements Parcelable {
public static final int TYPE_BCL_CURRENT = TemperatureType.BCL_CURRENT;
public static final int TYPE_BCL_PERCENTAGE = TemperatureType.BCL_PERCENTAGE;
public static final int TYPE_NPU = TemperatureType.NPU;
+ public static final int TYPE_TPU = TemperatureType.TPU;
+ public static final int TYPE_DISPLAY = TemperatureType.DISPLAY;
+ public static final int TYPE_MODEM = TemperatureType.MODEM;
+ public static final int TYPE_SOC = TemperatureType.SOC;
/**
* Verify a valid Temperature type.
@@ -98,7 +108,7 @@ public final class Temperature implements Parcelable {
* @return true if a Temperature type is valid otherwise false.
*/
public static boolean isValidType(@Type int type) {
- return type >= TYPE_UNKNOWN && type <= TYPE_NPU;
+ return type >= TYPE_UNKNOWN && type <= TYPE_SOC;
}
/**
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 9c8ee562849c..80041437d6b8 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -25,6 +25,9 @@ import android.content.pm.DataLoaderParams;
import android.content.pm.IPackageLoadingProgressCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
import android.util.Slog;
import android.util.SparseArray;
@@ -146,15 +149,29 @@ public final class IncrementalManager {
@Nullable
public IncrementalStorage createStorage(@NonNull String path,
@NonNull IncrementalStorage linkedStorage, @CreateMode int createMode) {
+ int id = -1;
try {
- final int id = mService.createLinkedStorage(
+ // Incremental service mounts its newly created storage on top of the supplied path,
+ // ensure that the original mode remains the same after mounting.
+ StructStat st = Os.stat(path);
+ id = mService.createLinkedStorage(
path, linkedStorage.getId(), createMode);
if (id < 0) {
return null;
}
+ Os.chmod(path, st.st_mode & 07777);
return new IncrementalStorage(mService, id);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (ErrnoException e) {
+ if (id >= 0) {
+ try {
+ mService.deleteStorage(id);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ throw new RuntimeException(e);
}
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 5527c69417d5..a72ccadd9829 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -17,7 +17,18 @@
package android.os.storage;
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
+import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.OP_READ_MEDIA_AUDIO;
+import static android.app.AppOpsManager.OP_READ_MEDIA_IMAGES;
+import static android.app.AppOpsManager.OP_READ_MEDIA_VIDEO;
+import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.OP_WRITE_MEDIA_AUDIO;
+import static android.app.AppOpsManager.OP_WRITE_MEDIA_IMAGES;
+import static android.app.AppOpsManager.OP_WRITE_MEDIA_VIDEO;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.PER_USER_RANGE;
@@ -1858,17 +1869,88 @@ public class StorageManager {
// handle obscure cases like when an app targets Q but was installed on
// a device that was originally running on P before being upgraded to Q.
- /**
- * @deprecated This method always returns false and should not be used.
- * Clients should check the appropriate permissions directly instead
- * (e.g. READ_MEDIA_IMAGES).
- *
- * {@hide}
- */
- @Deprecated
+ /** {@hide} */
+ public boolean checkPermissionReadAudio(boolean enforce,
+ int pid, int uid, String packageName, @Nullable String featureId) {
+ if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
+ READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) {
+ return false;
+ }
+ return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
+ OP_READ_MEDIA_AUDIO);
+ }
+
+ /** {@hide} */
+ public boolean checkPermissionWriteAudio(boolean enforce,
+ int pid, int uid, String packageName, @Nullable String featureId) {
+ if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
+ WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) {
+ return false;
+ }
+ return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
+ OP_WRITE_MEDIA_AUDIO);
+ }
+
+ /** {@hide} */
+ public boolean checkPermissionReadVideo(boolean enforce,
+ int pid, int uid, String packageName, @Nullable String featureId) {
+ if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
+ READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) {
+ return false;
+ }
+ return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
+ OP_READ_MEDIA_VIDEO);
+ }
+
+ /** {@hide} */
+ public boolean checkPermissionWriteVideo(boolean enforce,
+ int pid, int uid, String packageName, @Nullable String featureId) {
+ if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
+ WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) {
+ return false;
+ }
+ return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
+ OP_WRITE_MEDIA_VIDEO);
+ }
+
+ /** {@hide} */
public boolean checkPermissionReadImages(boolean enforce,
int pid, int uid, String packageName, @Nullable String featureId) {
- return false;
+ if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
+ READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) {
+ return false;
+ }
+ return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
+ OP_READ_MEDIA_IMAGES);
+ }
+
+ /** {@hide} */
+ public boolean checkPermissionWriteImages(boolean enforce,
+ int pid, int uid, String packageName, @Nullable String featureId) {
+ if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
+ WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) {
+ return false;
+ }
+ return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
+ OP_WRITE_MEDIA_IMAGES);
+ }
+
+ private boolean checkExternalStoragePermissionAndAppOp(boolean enforce,
+ int pid, int uid, String packageName, @Nullable String featureId, String permission,
+ int op) {
+ // First check if app has MANAGE_EXTERNAL_STORAGE.
+ final int mode = mAppOps.noteOpNoThrow(OP_MANAGE_EXTERNAL_STORAGE, uid, packageName,
+ featureId, null);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+ if (mode == AppOpsManager.MODE_DEFAULT && mContext.checkPermission(
+ MANAGE_EXTERNAL_STORAGE, pid, uid) == PERMISSION_GRANTED) {
+ return true;
+ }
+ // If app doesn't have MANAGE_EXTERNAL_STORAGE, then check if it has requested granular
+ // permission.
+ return checkPermissionAndAppOp(enforce, pid, uid, packageName, featureId, permission, op);
}
/** {@hide} */
@@ -2660,7 +2742,8 @@ public class StorageManager {
/** {@hide} */
@TestApi
- public static @NonNull UUID convert(@NonNull String uuid) {
+ public static @NonNull UUID convert(@Nullable String uuid) {
+ // UUID_PRIVATE_INTERNAL is null, so this accepts nullable input
if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
return UUID_DEFAULT;
} else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {
diff --git a/core/java/android/service/credentials/Action.java b/core/java/android/service/credentials/Action.java
index 77570813e6c3..42dd52840575 100644
--- a/core/java/android/service/credentials/Action.java
+++ b/core/java/android/service/credentials/Action.java
@@ -42,7 +42,7 @@ public final class Action implements Parcelable {
* level authentication before displaying any content etc.
*
* <p> See details on usage of {@code Action} for various actionable entries in
- * {@link BeginCreateCredentialResponse} and {@link GetCredentialsResponse}.
+ * {@link BeginCreateCredentialResponse} and {@link BeginGetCredentialsResponse}.
*
* @param slice the display content to be displayed on the UI, along with this action
* @param pendingIntent the intent to be invoked when the user selects this action
diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
index 022678ea49bd..8ca3a1a2ec99 100644
--- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
@@ -127,7 +127,7 @@ public final class BeginCreateCredentialResponse implements Parcelable {
*
* <p> Once the remote credential flow is complete, the {@link android.app.Activity}
* result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the
- * {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESULT} key should be populated
+ * {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE} key should be populated
* with a {@link android.credentials.CreateCredentialResponse} object.
*/
public @NonNull Builder setRemoteCreateEntry(@Nullable CreateEntry remoteCreateEntry) {
diff --git a/core/java/android/service/credentials/BeginGetCredentialOption.java b/core/java/android/service/credentials/BeginGetCredentialOption.java
new file mode 100644
index 000000000000..c82b445d19e0
--- /dev/null
+++ b/core/java/android/service/credentials/BeginGetCredentialOption.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.service.credentials;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A specific type of credential request to be sent to the provider during the query phase of
+ * a get flow. This request contains limited parameters needed to populate a list of
+ * {@link CredentialEntry} on the {@link BeginGetCredentialsResponse}.
+ */
+public final class BeginGetCredentialOption implements Parcelable {
+
+ /**
+ * The requested credential type.
+ */
+ @NonNull
+ private final String mType;
+
+ /**
+ * The request candidateQueryData.
+ */
+ @NonNull
+ private final Bundle mCandidateQueryData;
+
+ /**
+ * Returns the requested credential type.
+ */
+ @NonNull
+ public String getType() {
+ return mType;
+ }
+
+ /**
+ * Returns the request candidate query data, denoting a set of parameters
+ * that can be used to populate a candidate list of credentials, as
+ * {@link CredentialEntry} on {@link BeginGetCredentialsResponse}. This list
+ * of entries is then presented to the user on a selector.
+ *
+ * <p>This data does not contain any sensitive parameters, and will be sent
+ * to all eligible providers.
+ * The complete set of parameters will only be set on the {@link android.app.PendingIntent}
+ * set on the {@link CredentialEntry} that is selected by the user.
+ */
+ @NonNull
+ public Bundle getCandidateQueryData() {
+ return mCandidateQueryData;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mType);
+ dest.writeBundle(mCandidateQueryData);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "GetCredentialOption {"
+ + "type=" + mType
+ + ", candidateQueryData=" + mCandidateQueryData
+ + "}";
+ }
+
+ /**
+ * Constructs a {@link BeginGetCredentialOption}.
+ *
+ * @param type the requested credential type
+ * @param candidateQueryData the request candidateQueryData
+ *
+ * @throws IllegalArgumentException If type is empty.
+ */
+ public BeginGetCredentialOption(
+ @NonNull String type,
+ @NonNull Bundle candidateQueryData) {
+ mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
+ mCandidateQueryData = requireNonNull(
+ candidateQueryData, "candidateQueryData must not be null");
+ }
+
+ private BeginGetCredentialOption(@NonNull Parcel in) {
+ String type = in.readString8();
+ Bundle candidateQueryData = in.readBundle();
+
+ mType = type;
+ AnnotationValidations.validate(NonNull.class, null, mType);
+ mCandidateQueryData = candidateQueryData;
+ AnnotationValidations.validate(NonNull.class, null, mCandidateQueryData);
+ }
+
+ public static final @NonNull Creator<BeginGetCredentialOption> CREATOR =
+ new Creator<BeginGetCredentialOption>() {
+ @Override
+ public BeginGetCredentialOption[] newArray(int size) {
+ return new BeginGetCredentialOption[size];
+ }
+
+ @Override
+ public BeginGetCredentialOption createFromParcel(@NonNull Parcel in) {
+ return new BeginGetCredentialOption(in);
+ }
+ };
+}
diff --git a/core/java/android/service/credentials/GetCredentialsRequest.aidl b/core/java/android/service/credentials/BeginGetCredentialsRequest.aidl
index b309d698e7de..5e1fe8abc2aa 100644
--- a/core/java/android/service/credentials/GetCredentialsRequest.aidl
+++ b/core/java/android/service/credentials/BeginGetCredentialsRequest.aidl
@@ -1,3 +1,3 @@
package android.service.credentials;
-parcelable GetCredentialsRequest; \ No newline at end of file
+parcelable BeginGetCredentialsRequest; \ No newline at end of file
diff --git a/core/java/android/service/credentials/BeginGetCredentialsRequest.java b/core/java/android/service/credentials/BeginGetCredentialsRequest.java
new file mode 100644
index 000000000000..795840b42f2a
--- /dev/null
+++ b/core/java/android/service/credentials/BeginGetCredentialsRequest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.service.credentials;
+
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.credentials.GetCredentialOption;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Query stage request for getting user's credentials from a given credential provider.
+ *
+ * <p>This request contains a list of {@link GetCredentialOption} that have parameters
+ * to be used to query credentials, and return a list of {@link CredentialEntry} to be set
+ * on the {@link BeginGetCredentialsResponse}. This list is then shown to the user on a selector.
+ *
+ * If a {@link PendingIntent} is set on a {@link CredentialEntry}, and the user selects that
+ * entry, a {@link GetCredentialRequest} with all parameters needed to get the actual
+ * {@link android.credentials.Credential} will be sent as part of the {@link Intent} fired
+ * through the {@link PendingIntent}.
+ */
+public final class BeginGetCredentialsRequest implements Parcelable {
+ /** Calling package of the app requesting for credentials. */
+ @NonNull private final String mCallingPackage;
+
+ /**
+ * List of credential options. Each {@link BeginGetCredentialOption} object holds parameters to
+ * be used for populating a list of {@link CredentialEntry} for a specific type of credential.
+ *
+ * This request does not reveal sensitive parameters. Complete list of parameters
+ * is retrieved through the {@link PendingIntent} set on each {@link CredentialEntry}
+ * on {@link CredentialsResponseContent} set on {@link BeginGetCredentialsResponse},
+ * when the user selects one of these entries.
+ */
+ @NonNull private final List<BeginGetCredentialOption> mBeginGetCredentialOptions;
+
+ private BeginGetCredentialsRequest(@NonNull String callingPackage,
+ @NonNull List<BeginGetCredentialOption> getBeginCredentialOptions) {
+ this.mCallingPackage = callingPackage;
+ this.mBeginGetCredentialOptions = getBeginCredentialOptions;
+ }
+
+ private BeginGetCredentialsRequest(@NonNull Parcel in) {
+ mCallingPackage = in.readString8();
+ List<BeginGetCredentialOption> getBeginCredentialOptions = new ArrayList<>();
+ in.readTypedList(getBeginCredentialOptions, BeginGetCredentialOption.CREATOR);
+ mBeginGetCredentialOptions = getBeginCredentialOptions;
+ AnnotationValidations.validate(NonNull.class, null, mBeginGetCredentialOptions);
+ }
+
+ public static final @NonNull Creator<BeginGetCredentialsRequest> CREATOR =
+ new Creator<BeginGetCredentialsRequest>() {
+ @Override
+ public BeginGetCredentialsRequest createFromParcel(Parcel in) {
+ return new BeginGetCredentialsRequest(in);
+ }
+
+ @Override
+ public BeginGetCredentialsRequest[] newArray(int size) {
+ return new BeginGetCredentialsRequest[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mCallingPackage);
+ dest.writeTypedList(mBeginGetCredentialOptions);
+ }
+
+ /**
+ * Returns the calling package of the app requesting credentials.
+ */
+ public @NonNull String getCallingPackage() {
+ return mCallingPackage;
+ }
+
+ /**
+ * Returns the list of type specific credential options to list credentials for in
+ * {@link BeginGetCredentialsResponse}.
+ */
+ public @NonNull List<BeginGetCredentialOption> getBeginGetCredentialOptions() {
+ return mBeginGetCredentialOptions;
+ }
+
+ /**
+ * Builder for {@link BeginGetCredentialsRequest}.
+ */
+ public static final class Builder {
+ private String mCallingPackage;
+ private List<BeginGetCredentialOption> mBeginGetCredentialOptions = new ArrayList<>();
+
+ /**
+ * Creates a new builder.
+ * @param callingPackage the calling package of the app requesting credentials
+ *
+ * @throws IllegalArgumentException If {@code callingPackage} is null or empty.
+ */
+ public Builder(@NonNull String callingPackage) {
+ mCallingPackage = Preconditions.checkStringNotEmpty(callingPackage);
+ }
+
+ /**
+ * Sets the list of credential options.
+ *
+ * @throws NullPointerException If {@code getBeginCredentialOptions} itself or any of its
+ * elements is null.
+ * @throws IllegalArgumentException If {@code getBeginCredentialOptions} is empty.
+ */
+ public @NonNull Builder setBeginGetCredentialOptions(
+ @NonNull List<BeginGetCredentialOption> getBeginCredentialOptions) {
+ Preconditions.checkCollectionNotEmpty(getBeginCredentialOptions,
+ "getBeginCredentialOptions");
+ Preconditions.checkCollectionElementsNotNull(getBeginCredentialOptions,
+ "getBeginCredentialOptions");
+ mBeginGetCredentialOptions = getBeginCredentialOptions;
+ return this;
+ }
+
+ /**
+ * Adds a single {@link BeginGetCredentialOption} object to the list of credential options.
+ *
+ * @throws NullPointerException If {@code beginGetCredentialOption} is null.
+ */
+ public @NonNull Builder addBeginGetCredentialOption(
+ @NonNull BeginGetCredentialOption beginGetCredentialOption) {
+ Objects.requireNonNull(beginGetCredentialOption,
+ "beginGetCredentialOption must not be null");
+ mBeginGetCredentialOptions.add(beginGetCredentialOption);
+ return this;
+ }
+
+ /**
+ * Builds a new {@link BeginGetCredentialsRequest} instance.
+ *
+ * @throws NullPointerException If {@code beginGetCredentialOptions} is null.
+ * @throws IllegalArgumentException If {@code beginGetCredentialOptions} is empty, or if
+ * {@code callingPackage} is null or empty.
+ */
+ public @NonNull BeginGetCredentialsRequest build() {
+ Preconditions.checkStringNotEmpty(mCallingPackage,
+ "Must set the calling package");
+ Preconditions.checkCollectionNotEmpty(mBeginGetCredentialOptions,
+ "beginGetCredentialOptions");
+ return new BeginGetCredentialsRequest(mCallingPackage, mBeginGetCredentialOptions);
+ }
+ }
+}
diff --git a/core/java/android/service/credentials/BeginGetCredentialsResponse.aidl b/core/java/android/service/credentials/BeginGetCredentialsResponse.aidl
new file mode 100644
index 000000000000..ca69bcaa866b
--- /dev/null
+++ b/core/java/android/service/credentials/BeginGetCredentialsResponse.aidl
@@ -0,0 +1,3 @@
+package android.service.credentials;
+
+parcelable BeginGetCredentialsResponse; \ No newline at end of file
diff --git a/core/java/android/service/credentials/GetCredentialsResponse.java b/core/java/android/service/credentials/BeginGetCredentialsResponse.java
index 5263141f982a..2cda56067ba8 100644
--- a/core/java/android/service/credentials/GetCredentialsResponse.java
+++ b/core/java/android/service/credentials/BeginGetCredentialsResponse.java
@@ -27,7 +27,7 @@ import java.util.Objects;
* Response from a credential provider, containing credential entries and other associated
* data to be shown on the account selector UI.
*/
-public final class GetCredentialsResponse implements Parcelable {
+public final class BeginGetCredentialsResponse implements Parcelable {
/** Content to be used for the UI. */
private final @Nullable CredentialsResponseContent mCredentialsResponseContent;
@@ -38,14 +38,15 @@ public final class GetCredentialsResponse implements Parcelable {
private final @Nullable Action mAuthenticationAction;
/**
- * Creates a {@link GetCredentialsResponse} instance with an authentication {@link Action} set.
- * Providers must use this method when no content can be shown before authentication.
+ * Creates a {@link BeginGetCredentialsResponse} instance with an authentication
+ * {@link Action} set. Providers must use this method when no content can be shown
+ * before authentication.
*
* <p> When the user selects this {@code authenticationAction}, the system invokes the
* corresponding {@code pendingIntent}. Once the authentication flow is complete,
* the {@link android.app.Activity} result should be set
* to {@link android.app.Activity#RESULT_OK} and the
- * {@link CredentialProviderService#EXTRA_GET_CREDENTIALS_CONTENT_RESULT} extra should be set
+ * {@link CredentialProviderService#EXTRA_CREDENTIALS_RESPONSE_CONTENT} extra should be set
* with a fully populated {@link CredentialsResponseContent} object.
* the authentication action activity is launched, and the user is authenticated, providers
* should create another response with {@link CredentialsResponseContent} using
@@ -54,48 +55,49 @@ public final class GetCredentialsResponse implements Parcelable {
*
* @throws NullPointerException If {@code authenticationAction} is null.
*/
- public static @NonNull GetCredentialsResponse createWithAuthentication(
+ public static @NonNull BeginGetCredentialsResponse createWithAuthentication(
@NonNull Action authenticationAction) {
Objects.requireNonNull(authenticationAction,
"authenticationAction must not be null");
- return new GetCredentialsResponse(null, authenticationAction);
+ return new BeginGetCredentialsResponse(null, authenticationAction);
}
/**
- * Creates a {@link GetCredentialsRequest} instance with content to be shown on the UI.
+ * Creates a {@link BeginGetCredentialsRequest} instance with content to be shown on the UI.
* Providers must use this method when there is content to be shown without top level
* authentication required, including credential entries, action entries or a remote entry,
*
* @throws NullPointerException If {@code credentialsResponseContent} is null.
*/
- public static @NonNull GetCredentialsResponse createWithResponseContent(
+ public static @NonNull BeginGetCredentialsResponse createWithResponseContent(
@NonNull CredentialsResponseContent credentialsResponseContent) {
Objects.requireNonNull(credentialsResponseContent,
"credentialsResponseContent must not be null");
- return new GetCredentialsResponse(credentialsResponseContent, null);
+ return new BeginGetCredentialsResponse(credentialsResponseContent, null);
}
- private GetCredentialsResponse(@Nullable CredentialsResponseContent credentialsResponseContent,
+ private BeginGetCredentialsResponse(@Nullable CredentialsResponseContent
+ credentialsResponseContent,
@Nullable Action authenticationAction) {
mCredentialsResponseContent = credentialsResponseContent;
mAuthenticationAction = authenticationAction;
}
- private GetCredentialsResponse(@NonNull Parcel in) {
+ private BeginGetCredentialsResponse(@NonNull Parcel in) {
mCredentialsResponseContent = in.readTypedObject(CredentialsResponseContent.CREATOR);
mAuthenticationAction = in.readTypedObject(Action.CREATOR);
}
- public static final @NonNull Creator<GetCredentialsResponse> CREATOR =
- new Creator<GetCredentialsResponse>() {
+ public static final @NonNull Creator<BeginGetCredentialsResponse> CREATOR =
+ new Creator<BeginGetCredentialsResponse>() {
@Override
- public GetCredentialsResponse createFromParcel(Parcel in) {
- return new GetCredentialsResponse(in);
+ public BeginGetCredentialsResponse createFromParcel(Parcel in) {
+ return new BeginGetCredentialsResponse(in);
}
@Override
- public GetCredentialsResponse[] newArray(int size) {
- return new GetCredentialsResponse[size];
+ public BeginGetCredentialsResponse[] newArray(int size) {
+ return new BeginGetCredentialsResponse[size];
}
};
diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java
index 941db02be8d1..3c399d26c2fb 100644
--- a/core/java/android/service/credentials/CredentialEntry.java
+++ b/core/java/android/service/credentials/CredentialEntry.java
@@ -17,10 +17,9 @@
package android.service.credentials;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.slice.Slice;
-import android.credentials.Credential;
+import android.credentials.GetCredentialResponse;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,32 +40,23 @@ public final class CredentialEntry implements Parcelable {
private final @NonNull Slice mSlice;
/** The pending intent to be invoked when this credential entry is selected. */
- private final @Nullable PendingIntent mPendingIntent;
-
- /**
- * The underlying credential to be returned to the app when the user selects
- * this credential entry.
- */
- private final @Nullable Credential mCredential;
+ private final @NonNull PendingIntent mPendingIntent;
/** A flag denoting whether auto-select is enabled for this entry. */
private final @NonNull boolean mAutoSelectAllowed;
private CredentialEntry(@NonNull String type, @NonNull Slice slice,
- @Nullable PendingIntent pendingIntent, @Nullable Credential credential,
- @NonNull boolean autoSeletAllowed) {
+ @NonNull PendingIntent pendingIntent, @NonNull boolean autoSelectAllowed) {
mType = type;
mSlice = slice;
mPendingIntent = pendingIntent;
- mCredential = credential;
- mAutoSelectAllowed = autoSeletAllowed;
+ mAutoSelectAllowed = autoSelectAllowed;
}
private CredentialEntry(@NonNull Parcel in) {
mType = in.readString8();
mSlice = in.readTypedObject(Slice.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
- mCredential = in.readTypedObject(Credential.CREATOR);
mAutoSelectAllowed = in.readBoolean();
}
@@ -93,7 +83,6 @@ public final class CredentialEntry implements Parcelable {
dest.writeString8(mType);
dest.writeTypedObject(mSlice, flags);
dest.writeTypedObject(mPendingIntent, flags);
- dest.writeTypedObject(mCredential, flags);
dest.writeBoolean(mAutoSelectAllowed);
}
@@ -114,18 +103,11 @@ public final class CredentialEntry implements Parcelable {
/**
* Returns the pending intent to be invoked if the user selects this entry.
*/
- public @Nullable PendingIntent getPendingIntent() {
+ public @NonNull PendingIntent getPendingIntent() {
return mPendingIntent;
}
/**
- * Returns the credential associated with this entry.
- */
- public @Nullable Credential getCredential() {
- return mCredential;
- }
-
- /**
* Returns whether this entry can be auto selected if it is the only option for the user.
*/
public boolean isAutoSelectAllowed() {
@@ -138,8 +120,7 @@ public final class CredentialEntry implements Parcelable {
public static final class Builder {
private String mType;
private Slice mSlice;
- private PendingIntent mPendingIntent = null;
- private Credential mCredential = null;
+ private PendingIntent mPendingIntent;
private boolean mAutoSelectAllowed = false;
/**
@@ -152,8 +133,8 @@ public final class CredentialEntry implements Parcelable {
* Once the activity fulfills the required user engagement, the
* {@link android.app.Activity} result should be set to
* {@link android.app.Activity#RESULT_OK}, and the
- * {@link CredentialProviderService#EXTRA_CREDENTIAL_RESULT} must be set with a
- * {@link Credential} object.
+ * {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} must be set with a
+ * {@link GetCredentialResponse} object.
*
* @param type the type of credential underlying this credential entry
* @param slice the content to be displayed with this entry on the UI
@@ -179,26 +160,6 @@ public final class CredentialEntry implements Parcelable {
}
/**
- * Creates a builder for a {@link CredentialEntry} that contains a {@link Credential},
- * and does not require further action.
- * @param type the type of credential underlying this credential entry
- * @param slice the content to be displayed with this entry on the UI
- * @param credential the credential to be returned to the client app, when this entry is
- * selected by the user
- *
- * @throws IllegalArgumentException If {@code type} is null or empty.
- * @throws NullPointerException If {@code slice}, or {@code credential} is null.
- */
- public Builder(@NonNull String type, @NonNull Slice slice, @NonNull Credential credential) {
- mType = Preconditions.checkStringNotEmpty(type, "type must not be "
- + "null, or empty");
- mSlice = Objects.requireNonNull(slice,
- "slice must not be null");
- mCredential = Objects.requireNonNull(credential,
- "credential must not be null");
- }
-
- /**
* Sets whether the entry is allowed to be auto selected by the framework.
* The default value is set to false.
*
@@ -219,12 +180,9 @@ public final class CredentialEntry implements Parcelable {
* is set, or if both are set.
*/
public @NonNull CredentialEntry build() {
- Preconditions.checkState(((mPendingIntent != null && mCredential == null)
- || (mPendingIntent == null && mCredential != null)),
- "Either pendingIntent or credential must be set, and both cannot"
- + "be set at the same time");
- return new CredentialEntry(mType, mSlice, mPendingIntent,
- mCredential, mAutoSelectAllowed);
+ Preconditions.checkState(mPendingIntent != null,
+ "pendingIntent must not be null");
+ return new CredentialEntry(mType, mSlice, mPendingIntent, mAutoSelectAllowed);
}
}
}
diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java
index 32646e6fd289..416ddf172616 100644
--- a/core/java/android/service/credentials/CredentialProviderService.java
+++ b/core/java/android/service/credentials/CredentialProviderService.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.CancellationSignal;
@@ -45,12 +46,23 @@ public abstract class CredentialProviderService extends Service {
* returned as part of the {@link BeginCreateCredentialResponse}
*
* <p>
- * Type: {@link android.credentials.CreateCredentialRequest}
+ * Type: {@link android.service.credentials.CreateCredentialRequest}
*/
public static final String EXTRA_CREATE_CREDENTIAL_REQUEST =
"android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST";
/**
+ * Intent extra: The {@link GetCredentialRequest} attached with
+ * the {@code pendingIntent} that is invoked when the user selects a {@link CredentialEntry}
+ * returned as part of the {@link BeginGetCredentialsResponse}
+ *
+ * <p>
+ * Type: {@link GetCredentialRequest}
+ */
+ public static final String EXTRA_GET_CREDENTIAL_REQUEST =
+ "android.service.credentials.extra.GET_CREDENTIAL_REQUEST";
+
+ /**
* Intent extra: The result of a create flow operation, to be set on finish of the
* {@link android.app.Activity} invoked through the {@code pendingIntent} set on
* a {@link CreateEntry}.
@@ -58,8 +70,8 @@ public abstract class CredentialProviderService extends Service {
* <p>
* Type: {@link android.credentials.CreateCredentialResponse}
*/
- public static final String EXTRA_CREATE_CREDENTIAL_RESULT =
- "android.service.credentials.extra.CREATE_CREDENTIAL_RESULT";
+ public static final String EXTRA_CREATE_CREDENTIAL_RESPONSE =
+ "android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE";
/**
* Intent extra: The result of a get credential flow operation, to be set on finish of the
@@ -67,33 +79,48 @@ public abstract class CredentialProviderService extends Service {
* a {@link CredentialEntry}.
*
* <p>
- * Type: {@link android.credentials.Credential}
+ * Type: {@link android.credentials.GetCredentialResponse}
*/
- public static final String EXTRA_CREDENTIAL_RESULT =
- "android.service.credentials.extra.CREDENTIAL_RESULT";
+ public static final String EXTRA_GET_CREDENTIAL_RESPONSE =
+ "android.service.credentials.extra.GET_CREDENTIAL_RESPONSE";
/**
* Intent extra: The result of an authentication flow, to be set on finish of the
* {@link android.app.Activity} invoked through the {@link android.app.PendingIntent} set on
- * a {@link GetCredentialsResponse}. This result should contain the actual content, including
- * credential entries and action entries, to be shown on the selector.
+ * a {@link BeginGetCredentialsResponse}. This result should contain the actual content,
+ * including credential entries and action entries, to be shown on the selector.
*
* <p>
* Type: {@link CredentialsResponseContent}
*/
- public static final String EXTRA_GET_CREDENTIALS_CONTENT_RESULT =
- "android.service.credentials.extra.GET_CREDENTIALS_CONTENT_RESULT";
+ public static final String EXTRA_CREDENTIALS_RESPONSE_CONTENT =
+ "android.service.credentials.extra.CREDENTIALS_RESPONSE_CONTENT";
/**
- * Intent extra: The error result of any {@link android.app.PendingIntent} flow, to be set
- * on finish of the corresponding {@link android.app.Activity}. This result should contain an
- * error code, representing the error encountered by the provider.
+ * Intent extra: The failure exception set at the final stage of a get flow.
+ * This exception is set at the finishing result of the {@link android.app.Activity}
+ * invoked by the {@link PendingIntent} , when a user selects the {@link CredentialEntry}
+ * that contained the {@link PendingIntent} in question.
+ *
+ * <p>The result must be set through {@link android.app.Activity#setResult} as an intent extra
*
* <p>
- * Type: {@link String}
+ * Type: {@link android.credentials.GetCredentialException}
*/
- public static final String EXTRA_ERROR =
- "android.service.credentials.extra.ERROR";
+ public static final String EXTRA_GET_CREDENTIAL_EXCEPTION =
+ "android.service.credentials.extra.GET_CREDENTIAL_EXCEPTION";
+
+ /**
+ * Intent extra: The failure exception set at the final stage of a create flow.
+ * This exception is set at the finishing result of the {@link android.app.Activity}
+ * invoked by the {@link PendingIntent} , when a user selects the {@link CreateEntry}
+ * that contained the {@link PendingIntent} in question.
+ *
+ * <p>
+ * Type: {@link android.credentials.CreateCredentialException}
+ */
+ public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION =
+ "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION";
private static final String TAG = "CredProviderService";
@@ -128,20 +155,21 @@ public abstract class CredentialProviderService extends Service {
private final ICredentialProviderService mInterface = new ICredentialProviderService.Stub() {
@Override
- public ICancellationSignal onGetCredentials(GetCredentialsRequest request,
- IGetCredentialsCallback callback) {
+ public ICancellationSignal onBeginGetCredentials(BeginGetCredentialsRequest request,
+ IBeginGetCredentialsCallback callback) {
Objects.requireNonNull(request);
Objects.requireNonNull(callback);
ICancellationSignal transport = CancellationSignal.createTransport();
mHandler.sendMessage(obtainMessage(
- CredentialProviderService::onGetCredentials,
+ CredentialProviderService::onBeginGetCredentials,
CredentialProviderService.this, request,
CancellationSignal.fromTransport(transport),
- new OutcomeReceiver<GetCredentialsResponse, CredentialProviderException>() {
+ new OutcomeReceiver<BeginGetCredentialsResponse,
+ CredentialProviderException>() {
@Override
- public void onResult(GetCredentialsResponse result) {
+ public void onResult(BeginGetCredentialsResponse result) {
try {
callback.onSuccess(result);
} catch (RemoteException e) {
@@ -200,14 +228,29 @@ public abstract class CredentialProviderService extends Service {
/**
* Called by the android system to retrieve user credentials from the connected provider
* service.
- * @param request the credential request for the provider to handle
+ *
+ *
+ *
+ * <p>This API denotes a query stage request for getting user's credentials from a given
+ * credential provider. The request contains a list of
+ * {@link android.credentials.GetCredentialOption} that have parameters to be used for
+ * populating candidate credentials, as a list of {@link CredentialEntry} to be set
+ * on the {@link BeginGetCredentialsResponse}. This list is then shown to the user on a
+ * selector.
+ *
+ * <p>If a {@link PendingIntent} is set on a {@link CredentialEntry}, and the user selects that
+ * entry, a {@link GetCredentialRequest} with all parameters needed to get the actual
+ * {@link android.credentials.Credential} will be sent as part of the {@link Intent} fired
+ * through the {@link PendingIntent}.
+ * @param request the request for the provider to handle
* @param cancellationSignal signal for providers to listen to any cancellation requests from
* the android system
* @param callback object used to relay the response of the credentials request
*/
- public abstract void onGetCredentials(@NonNull GetCredentialsRequest request,
+ public abstract void onBeginGetCredentials(@NonNull BeginGetCredentialsRequest request,
@NonNull CancellationSignal cancellationSignal,
- @NonNull OutcomeReceiver<GetCredentialsResponse, CredentialProviderException> callback);
+ @NonNull OutcomeReceiver<
+ BeginGetCredentialsResponse, CredentialProviderException> callback);
/**
* Called by the android system to create a credential.
diff --git a/core/java/android/service/credentials/CredentialsResponseContent.java b/core/java/android/service/credentials/CredentialsResponseContent.java
index 32cab5004ac0..c2f28cb1204c 100644
--- a/core/java/android/service/credentials/CredentialsResponseContent.java
+++ b/core/java/android/service/credentials/CredentialsResponseContent.java
@@ -29,7 +29,7 @@ import java.util.Objects;
/**
* The content to be displayed on the account selector UI, including credential entries,
- * actions etc. Returned as part of {@link GetCredentialsResponse}
+ * actions etc. Returned as part of {@link BeginGetCredentialsResponse}
*/
public final class CredentialsResponseContent implements Parcelable {
/** List of credential entries to be displayed on the UI. */
@@ -124,7 +124,7 @@ public final class CredentialsResponseContent implements Parcelable {
*
* <p> Once the remote credential flow is complete, the {@link android.app.Activity}
* result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the
- * {@link CredentialProviderService#EXTRA_CREDENTIAL_RESULT} key should be populated
+ * {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} key should be populated
* with a {@link android.credentials.Credential} object.
*/
public @NonNull Builder setRemoteCredentialEntry(@Nullable CredentialEntry
@@ -188,7 +188,7 @@ public final class CredentialsResponseContent implements Parcelable {
}
/**
- * Builds a {@link GetCredentialsResponse} instance.
+ * Builds a {@link CredentialsResponseContent} instance.
*
* @throws IllegalStateException if {@code credentialEntries}, {@code actions}
* and {@code remoteCredentialEntry} are all null or empty.
diff --git a/core/java/android/service/credentials/GetCredentialsRequest.java b/core/java/android/service/credentials/GetCredentialRequest.java
index 9052b54c8291..1d6c83be0db1 100644
--- a/core/java/android/service/credentials/GetCredentialsRequest.java
+++ b/core/java/android/service/credentials/GetCredentialRequest.java
@@ -21,6 +21,7 @@ import android.credentials.GetCredentialOption;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.AnnotationValidations;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
@@ -30,7 +31,7 @@ import java.util.Objects;
/**
* Request for getting user's credentials from a given credential provider.
*/
-public final class GetCredentialsRequest implements Parcelable {
+public final class GetCredentialRequest implements Parcelable {
/** Calling package of the app requesting for credentials. */
private final @NonNull String mCallingPackage;
@@ -40,29 +41,30 @@ public final class GetCredentialsRequest implements Parcelable {
*/
private final @NonNull List<GetCredentialOption> mGetCredentialOptions;
- private GetCredentialsRequest(@NonNull String callingPackage,
+ private GetCredentialRequest(@NonNull String callingPackage,
@NonNull List<GetCredentialOption> getCredentialOptions) {
this.mCallingPackage = callingPackage;
this.mGetCredentialOptions = getCredentialOptions;
}
- private GetCredentialsRequest(@NonNull Parcel in) {
+ private GetCredentialRequest(@NonNull Parcel in) {
mCallingPackage = in.readString8();
List<GetCredentialOption> getCredentialOptions = new ArrayList<>();
in.readTypedList(getCredentialOptions, GetCredentialOption.CREATOR);
mGetCredentialOptions = getCredentialOptions;
+ AnnotationValidations.validate(NonNull.class, null, mGetCredentialOptions);
}
- public static final @NonNull Creator<GetCredentialsRequest> CREATOR =
- new Creator<GetCredentialsRequest>() {
+ public static final @NonNull Creator<GetCredentialRequest> CREATOR =
+ new Creator<GetCredentialRequest>() {
@Override
- public GetCredentialsRequest createFromParcel(Parcel in) {
- return new GetCredentialsRequest(in);
+ public GetCredentialRequest createFromParcel(Parcel in) {
+ return new GetCredentialRequest(in);
}
@Override
- public GetCredentialsRequest[] newArray(int size) {
- return new GetCredentialsRequest[size];
+ public GetCredentialRequest[] newArray(int size) {
+ return new GetCredentialRequest[size];
}
};
@@ -92,7 +94,7 @@ public final class GetCredentialsRequest implements Parcelable {
}
/**
- * Builder for {@link GetCredentialsRequest}.
+ * Builder for {@link GetCredentialRequest}.
*/
public static final class Builder {
private String mCallingPackage;
@@ -139,18 +141,18 @@ public final class GetCredentialsRequest implements Parcelable {
}
/**
- * Builds a new {@link GetCredentialsRequest} instance.
+ * Builds a new {@link GetCredentialRequest} instance.
*
* @throws NullPointerException If {@code getCredentialOptions} is null.
* @throws IllegalArgumentException If {@code getCredentialOptions} is empty, or if
* {@code callingPackage} is null or empty.
*/
- public @NonNull GetCredentialsRequest build() {
+ public @NonNull GetCredentialRequest build() {
Preconditions.checkStringNotEmpty(mCallingPackage,
"Must set the calling package");
Preconditions.checkCollectionNotEmpty(mGetCredentialOptions,
"getCredentialOptions");
- return new GetCredentialsRequest(mCallingPackage, mGetCredentialOptions);
+ return new GetCredentialRequest(mCallingPackage, mGetCredentialOptions);
}
}
}
diff --git a/core/java/android/service/credentials/GetCredentialsResponse.aidl b/core/java/android/service/credentials/GetCredentialsResponse.aidl
deleted file mode 100644
index 0d8c6357a715..000000000000
--- a/core/java/android/service/credentials/GetCredentialsResponse.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.service.credentials;
-
-parcelable GetCredentialsResponse; \ No newline at end of file
diff --git a/core/java/android/service/credentials/IGetCredentialsCallback.aidl b/core/java/android/service/credentials/IBeginGetCredentialsCallback.aidl
index 6e20c555af60..9ac28f26059b 100644
--- a/core/java/android/service/credentials/IGetCredentialsCallback.aidl
+++ b/core/java/android/service/credentials/IBeginGetCredentialsCallback.aidl
@@ -1,13 +1,13 @@
package android.service.credentials;
-import android.service.credentials.GetCredentialsResponse;
+import android.service.credentials.BeginGetCredentialsResponse;
/**
* Interface from the system to a credential provider service.
*
* @hide
*/
-oneway interface IGetCredentialsCallback {
- void onSuccess(in GetCredentialsResponse response);
+oneway interface IBeginGetCredentialsCallback {
+ void onSuccess(in BeginGetCredentialsResponse response);
void onFailure(int errorCode, in CharSequence message);
} \ No newline at end of file
diff --git a/core/java/android/service/credentials/ICredentialProviderService.aidl b/core/java/android/service/credentials/ICredentialProviderService.aidl
index b9eb3ed9571a..130688291795 100644
--- a/core/java/android/service/credentials/ICredentialProviderService.aidl
+++ b/core/java/android/service/credentials/ICredentialProviderService.aidl
@@ -17,9 +17,9 @@
package android.service.credentials;
import android.os.ICancellationSignal;
-import android.service.credentials.GetCredentialsRequest;
+import android.service.credentials.BeginGetCredentialsRequest;
import android.service.credentials.BeginCreateCredentialRequest;
-import android.service.credentials.IGetCredentialsCallback;
+import android.service.credentials.IBeginGetCredentialsCallback;
import android.service.credentials.IBeginCreateCredentialCallback;
import android.os.ICancellationSignal;
@@ -29,6 +29,6 @@ import android.os.ICancellationSignal;
* @hide
*/
interface ICredentialProviderService {
- ICancellationSignal onGetCredentials(in GetCredentialsRequest request, in IGetCredentialsCallback callback);
+ ICancellationSignal onBeginGetCredentials(in BeginGetCredentialsRequest request, in IBeginGetCredentialsCallback callback);
ICancellationSignal onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback);
}
diff --git a/core/java/android/service/voice/AbstractHotwordDetector.java b/core/java/android/service/voice/AbstractHotwordDetector.java
index 5d3852b8e81e..28357efeafd0 100644
--- a/core/java/android/service/voice/AbstractHotwordDetector.java
+++ b/core/java/android/service/voice/AbstractHotwordDetector.java
@@ -75,7 +75,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
/**
* Detect hotword from an externally supplied stream of data.
*
- * @return true if the request to start recognition succeeded
+ * @return {@code true} if the request to start recognition succeeded
*/
@Override
public boolean startRecognition(
@@ -102,23 +102,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
return true;
}
- /**
- * Set configuration and pass read-only data to hotword detection service.
- *
- * @param options Application configuration data to provide to the
- * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable
- * objects or other contents that can be used to communicate with other processes.
- * @param sharedMemory The unrestricted data blob to provide to the
- * {@link HotwordDetectionService}. Use this to provide the hotword models data or other
- * such data to the trusted process.
- * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of
- * Android Tiramisu or above and attempts to start a recognition when the detector is
- * not able based on the state. Because the caller receives updates via an asynchronous
- * callback and the state of the detector can change without caller's knowledge, a
- * checked exception is thrown.
- * @throws IllegalStateException if this HotwordDetector wasn't specified to use a
- * {@link HotwordDetectionService} when it was created.
- */
+ /** {@inheritDoc} */
@Override
public void updateState(@Nullable PersistableBundle options,
@Nullable SharedMemory sharedMemory) throws IllegalDetectorStateException {
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index d58f6d35981f..320280b9e68b 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -728,53 +728,24 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
*/
public abstract void onDetected(@NonNull EventPayload eventPayload);
- /**
- * Called when the detection fails due to an error.
- */
+ /** {@inheritDoc} */
public abstract void onError();
- /**
- * Called when the recognition is paused temporarily for some reason.
- * This is an informational callback, and the clients shouldn't be doing anything here
- * except showing an indication on their UI if they have to.
- */
+ /** {@inheritDoc} */
public abstract void onRecognitionPaused();
- /**
- * Called when the recognition is resumed after it was temporarily paused.
- * This is an informational callback, and the clients shouldn't be doing anything here
- * except showing an indication on their UI if they have to.
- */
+ /** {@inheritDoc} */
public abstract void onRecognitionResumed();
- /**
- * Called when the {@link HotwordDetectionService second stage detection} did not detect the
- * keyphrase.
- *
- * @param result Info about the second stage detection result, provided by the
- * {@link HotwordDetectionService}.
- */
+ /** {@inheritDoc} */
public void onRejected(@NonNull HotwordRejectedResult result) {
}
- /**
- * Called when the {@link HotwordDetectionService} is created by the system and given a
- * short amount of time to report it's initialization state.
- *
- * @param status Info about initialization state of {@link HotwordDetectionService}; the
- * allowed values are {@link HotwordDetectionService#INITIALIZATION_STATUS_SUCCESS},
- * 1<->{@link HotwordDetectionService#getMaxCustomInitializationStatus()},
- * {@link HotwordDetectionService#INITIALIZATION_STATUS_UNKNOWN}.
- */
+ /** {@inheritDoc} */
public void onHotwordDetectionServiceInitialized(int status) {
}
- /**
- * Called with the {@link HotwordDetectionService} is restarted.
- *
- * Clients are expected to call {@link HotwordDetector#updateState} to share the state with
- * the newly created service.
- */
+ /** {@inheritDoc} */
public void onHotwordDetectionServiceRestarted() {
}
}
@@ -785,14 +756,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* @param callback A non-null Callback for receiving the recognition events.
* @param modelManagementService A service that allows management of sound models.
* @param targetSdkVersion The target SDK version.
- * @param supportHotwordDetectionService {@code true} if hotword detection service should be
+ * @param supportHotwordDetectionService {@code true} if HotwordDetectionService should be
* triggered, otherwise {@code false}.
- * @param options Application configuration data provided by the
- * {@link VoiceInteractionService}. PersistableBundle does not allow any remotable objects or
- * other contents that can be used to communicate with other processes.
- * @param sharedMemory The unrestricted data blob provided by the
- * {@link VoiceInteractionService}. Use this to provide the hotword models data or other
- * such data to the trusted process.
*
* @hide
*/
@@ -1422,10 +1387,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
return mKeyphraseEnrollmentInfo.getManageKeyphraseIntent(action, mText, mLocale);
}
- /**
- * Invalidates this hotword detector so that any future calls to this result
- * in an IllegalStateException.
- */
+ /** {@inheritDoc} */
@Override
public void destroy() {
synchronized (mLock) {
diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java
index 1a0dc8945b63..7112dc666509 100644
--- a/core/java/android/service/voice/HotwordDetector.java
+++ b/core/java/android/service/voice/HotwordDetector.java
@@ -96,7 +96,7 @@ public interface HotwordDetector {
* <p>
* Calling this again while recognition is active does nothing.
*
- * @return true if the request to start recognition succeeded
+ * @return {@code true} if the request to start recognition succeeded
* @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
* or above and attempts to start a recognition when the detector is not able based on
* the state. This can be thrown even if the state has been checked before calling this
@@ -109,7 +109,7 @@ public interface HotwordDetector {
/**
* Stops hotword recognition.
*
- * @return true if the request to stop recognition succeeded
+ * @return {@code true} if the request to stop recognition succeeded
* @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
* or above and attempts to stop a recognition when the detector is not able based on
* the state. This can be thrown even if the state has been checked before calling this
@@ -129,7 +129,7 @@ public interface HotwordDetector {
* source of the audio. This will be provided to the {@link HotwordDetectionService}.
* PersistableBundle does not allow any remotable objects or other contents that can be
* used to communicate with other processes.
- * @return true if the request to start recognition succeeded
+ * @return {@code true} if the request to start recognition succeeded
* @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33
* or above and attempts to start a recognition when the detector is not able based on
* the state. This can be thrown even if the state has been checked before calling this
@@ -164,7 +164,9 @@ public interface HotwordDetector {
/**
* Invalidates this hotword detector so that any future calls to this result
- * in an {@link IllegalStateException}.
+ * in an {@link IllegalStateException} when a caller has a target SDK below API level 33
+ * or an {@link IllegalDetectorStateException} when a caller has a target SDK of API level 33
+ * or above.
*
* <p>If there are no other {@link HotwordDetector} instances linked to the
* {@link HotwordDetectionService}, the service will be shutdown.
@@ -234,7 +236,7 @@ public interface HotwordDetector {
void onRecognitionResumed();
/**
- * Called when the {@link HotwordDetectionService second stage detection} did not detect the
+ * Called when the {@link HotwordDetectionService} second stage detection did not detect the
* keyphrase.
*
* @param result Info about the second stage detection result, provided by the
@@ -244,7 +246,7 @@ public interface HotwordDetector {
/**
* Called when the {@link HotwordDetectionService} is created by the system and given a
- * short amount of time to report it's initialization state.
+ * short amount of time to report its initialization state.
*
* @param status Info about initialization state of {@link HotwordDetectionService}; the
* allowed values are {@link HotwordDetectionService#INITIALIZATION_STATUS_SUCCESS},
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 84a233ffd2ad..9d95d0b705ef 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -394,7 +394,7 @@ public abstract class WallpaperService extends Service {
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
- int syncSeqId, int resizeMode) {
+ int syncSeqId, boolean dragResizing) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0,
mergedConfiguration);
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 959295b883d5..101a0714bbf4 100755
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -20,12 +20,23 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.FontScaleConverter;
import android.os.SystemProperties;
+import android.view.WindowManager;
/**
* A structure describing general information about a display, such as its
* size, density, and font scaling.
* <p>To access the DisplayMetrics members, retrieve display metrics like this:</p>
* <pre>context.getResources().getDisplayMetrics();</pre>
+ *
+ * <p>
+ * For UI layout, obtain {@link android.view.WindowMetrics} from
+ * {@link WindowManager#getCurrentWindowMetrics()}. {@code DisplayMetrics} should only be used for
+ * obtaining display related properties, such as {@link #xdpi} and {@link #ydpi}
+ * </p><p>
+ * See {@link #density} for more information about the differences between {@link #xdpi},
+ * {@link #ydpi} and {@link #density}.
+ * </p>
+ *
*/
public class DisplayMetrics {
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 4277d01c091a..2c4f38de2db0 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -52,16 +52,6 @@ public class FeatureFlagUtils {
public static final String SETTINGS_SUPPORT_LARGE_SCREEN = "settings_support_large_screen";
/**
- * Feature flag to allow/restrict intent redirection from/to clone profile.
- * Default value is false,this is to ensure that framework is not impacted by intent redirection
- * till we are ready to launch.
- * From Android U onwards, this would be set to true and eventually removed.
- * @hide
- */
- public static final String SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE =
- "settings_allow_intent_redirection_for_clone_profile";
-
- /**
* Support locale opt-out and opt-in switch for per app's language.
* @hide
*/
@@ -174,7 +164,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true");
DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true");
DEFAULT_FLAGS.put("settings_search_always_expand", "true");
- DEFAULT_FLAGS.put(SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, "false");
DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true");
DEFAULT_FLAGS.put(SETTINGS_VOLUME_PANEL_IN_SYSTEMUI, "false");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
@@ -196,7 +185,6 @@ public class FeatureFlagUtils {
static {
PERSISTENT_FLAGS = new HashSet<>();
- PERSISTENT_FLAGS.add(SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE);
PERSISTENT_FLAGS.add(SETTINGS_APP_LOCALE_OPT_IN_ENABLED);
PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index a42d3eb9a2d2..71030bcc4723 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1469,7 +1469,8 @@ public final class Display {
* @param outMetrics A {@link DisplayMetrics} object which receives the display metrics.
*
* @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application
- * window. Use {@link Configuration#densityDpi} to get the display density.
+ * window. Use {@link WindowMetrics#getDensity()} to get the density of the application
+ * window.
*/
@Deprecated
public void getMetrics(DisplayMetrics outMetrics) {
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8e16f24b154f..d554514349c3 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -57,7 +57,7 @@ oneway interface IWindow {
void resized(in ClientWindowFrames frames, boolean reportDraw,
in MergedConfiguration newMergedConfiguration, in InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
- int syncSeqId, int resizeMode);
+ int syncSeqId, boolean dragResizing);
/**
* Called when this window retrieved control over a specified set of insets sources.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 6d9f99f76958..0aba80db5378 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -457,12 +457,6 @@ interface IWindowManager
int getDockedStackSide();
/**
- * Sets the region the user can touch the divider. This region will be excluded from the region
- * which is used to cause a focus switch when dispatching touch.
- */
- void setDockedTaskDividerTouchRegion(in Rect touchableRegion);
-
- /**
* Registers a listener that will be called when the pinned task state changes.
*/
void registerPinnedTaskListener(int displayId, IPinnedTaskListener listener);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 06c1b258cb70..61582cdf07a7 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -892,13 +892,18 @@ public class KeyEvent extends InputEvent implements Parcelable {
* The use of this button does not usually correspond to the function of an eraser.
*/
public static final int KEYCODE_STYLUS_BUTTON_TAIL = 311;
+ /**
+ * Key code constant: To open recent apps view (a.k.a. Overview).
+ * This key is handled by the framework and is never delivered to applications.
+ */
+ public static final int KEYCODE_RECENT_APPS = 312;
/**
* Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
* @hide
*/
@TestApi
- public static final int LAST_KEYCODE = KEYCODE_STYLUS_BUTTON_TAIL;
+ public static final int LAST_KEYCODE = KEYCODE_RECENT_APPS;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -2021,6 +2026,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
case KeyEvent.KEYCODE_MENU:
case KeyEvent.KEYCODE_SOFT_RIGHT:
case KeyEvent.KEYCODE_HOME:
+ case KeyEvent.KEYCODE_RECENT_APPS:
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_CALL:
case KeyEvent.KEYCODE_ENDCALL:
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 277b90cc04bc..5e8e1916f3c7 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -275,6 +275,7 @@ public final class SurfaceControl implements Parcelable {
int l, int t, int r, int b);
private static native void nativeSetDefaultApplyToken(IBinder token);
private static native IBinder nativeGetDefaultApplyToken();
+ private static native boolean nativeBootFinished();
/**
@@ -2376,6 +2377,14 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Lets surfaceFlinger know the boot procedure is completed.
+ * @hide
+ */
+ public static boolean bootFinished() {
+ return nativeBootFinished();
+ }
+
+ /**
* Interface to handle request to
* {@link SurfaceControl.Transaction#addTransactionCommittedListener(Executor, TransactionCommittedListener)}
*/
@@ -3870,4 +3879,5 @@ public final class SurfaceControl implements Parcelable {
SyncFence fence = new SyncFence(nativeFencePtr);
callback.accept(fence);
}
+
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 727011c5a94f..eaa6820c6864 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -51,8 +51,6 @@ import static android.view.ViewRootImplProto.WIDTH;
import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
import static android.view.ViewRootImplProto.WIN_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
-import static android.view.WindowCallbacks.RESIZE_MODE_INVALID;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -515,7 +513,6 @@ public final class ViewRootImpl implements ViewParent,
private boolean mPendingDragResizing;
private boolean mDragResizing;
private boolean mInvalidateRootRequested;
- private int mResizeMode = RESIZE_MODE_INVALID;
private int mCanvasOffsetX;
private int mCanvasOffsetY;
private boolean mActivityRelaunched;
@@ -1793,7 +1790,7 @@ public final class ViewRootImpl implements ViewParent,
CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration);
final boolean forceNextWindowRelayout = args.argi1 != 0;
final int displayId = args.argi3;
- final int resizeMode = args.argi5;
+ final boolean dragResizing = args.argi5 != 0;
final Rect frame = frames.frame;
final Rect displayFrame = frames.displayFrame;
@@ -1809,16 +1806,14 @@ public final class ViewRootImpl implements ViewParent,
final boolean attachedFrameChanged = LOCAL_LAYOUT
&& !Objects.equals(mTmpFrames.attachedFrame, attachedFrame);
final boolean displayChanged = mDisplay.getDisplayId() != displayId;
- final boolean resizeModeChanged = mResizeMode != resizeMode;
final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale;
if (msg == MSG_RESIZED && !frameChanged && !configChanged && !attachedFrameChanged
- && !displayChanged && !resizeModeChanged && !forceNextWindowRelayout
+ && !displayChanged && !forceNextWindowRelayout
&& !compatScaleChanged) {
return;
}
- mPendingDragResizing = resizeMode != RESIZE_MODE_INVALID;
- mResizeMode = resizeMode;
+ mPendingDragResizing = dragResizing;
mTmpFrames.compatScale = compatScale;
mInvCompatScale = 1f / compatScale;
@@ -3015,7 +3010,7 @@ public final class ViewRootImpl implements ViewParent,
frame.width() < desiredWindowWidth && frame.width() != mWidth)
|| (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.height() < desiredWindowHeight && frame.height() != mHeight));
- windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
+ windowShouldResize |= mDragResizing && mPendingDragResizing;
// If the activity was just relaunched, it might have unfrozen the task bounds (while
// relaunching), so we need to force a call into window manager to pick up the latest
@@ -3262,7 +3257,7 @@ public final class ViewRootImpl implements ViewParent,
&& mWinFrame.height() == mPendingBackDropFrame.height();
// TODO: Need cutout?
startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame,
- mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mResizeMode);
+ mAttachInfo.mContentInsets, mAttachInfo.mStableInsets);
} else {
// We shouldn't come here, but if we come we should end the resize.
endDragResizing();
@@ -3820,43 +3815,7 @@ public final class ViewRootImpl implements ViewParent,
}
if (mAdded) {
- profileRendering(hasWindowFocus);
- if (hasWindowFocus) {
- if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
- mFullRedrawNeeded = true;
- try {
- final Rect surfaceInsets = mWindowAttributes.surfaceInsets;
- mAttachInfo.mThreadedRenderer.initializeIfNeeded(
- mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
- } catch (OutOfResourcesException e) {
- Log.e(mTag, "OutOfResourcesException locking surface", e);
- try {
- if (!mWindowSession.outOfMemory(mWindow)) {
- Slog.w(mTag, "No processes killed for memory;"
- + " killing self");
- Process.killProcess(Process.myPid());
- }
- } catch (RemoteException ex) {
- }
- // Retry in a bit.
- mHandler.sendMessageDelayed(mHandler.obtainMessage(
- MSG_WINDOW_FOCUS_CHANGED), 500);
- return;
- }
- }
- }
-
- mAttachInfo.mHasWindowFocus = hasWindowFocus;
- mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes);
-
- if (mView != null) {
- mAttachInfo.mKeyDispatchState.reset();
- mView.dispatchWindowFocusChanged(hasWindowFocus);
- mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
- if (mAttachInfo.mTooltipHost != null) {
- mAttachInfo.mTooltipHost.hideTooltip();
- }
- }
+ dispatchFocusEvent(hasWindowFocus);
// Note: must be done after the focus change callbacks,
// so all of the view state is set up correctly.
@@ -3894,6 +3853,44 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ private void dispatchFocusEvent(boolean hasWindowFocus) {
+ profileRendering(hasWindowFocus);
+ if (hasWindowFocus && mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
+ mFullRedrawNeeded = true;
+ try {
+ final Rect surfaceInsets = mWindowAttributes.surfaceInsets;
+ mAttachInfo.mThreadedRenderer.initializeIfNeeded(
+ mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
+ } catch (OutOfResourcesException e) {
+ Log.e(mTag, "OutOfResourcesException locking surface", e);
+ try {
+ if (!mWindowSession.outOfMemory(mWindow)) {
+ Slog.w(mTag, "No processes killed for memory;"
+ + " killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
+ }
+ // Retry in a bit.
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_WINDOW_FOCUS_CHANGED), 500);
+ return;
+ }
+ }
+
+ mAttachInfo.mHasWindowFocus = hasWindowFocus;
+ mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes);
+
+ if (mView != null) {
+ mAttachInfo.mKeyDispatchState.reset();
+ mView.dispatchWindowFocusChanged(hasWindowFocus);
+ mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
+ if (mAttachInfo.mTooltipHost != null) {
+ mAttachInfo.mTooltipHost.hideTooltip();
+ }
+ }
+ }
+
private void handleWindowTouchModeChanged() {
final boolean inTouchMode;
synchronized (this) {
@@ -8828,7 +8825,7 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing) {
Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
SomeArgs args = SomeArgs.obtain();
final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
@@ -8850,7 +8847,7 @@ public final class ViewRootImpl implements ViewParent,
args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
args.argi3 = displayId;
args.argi4 = syncSeqId;
- args.argi5 = resizeMode;
+ args.argi5 = dragResizing ? 1 : 0;
msg.obj = args;
mHandler.sendMessage(msg);
@@ -10242,11 +10239,11 @@ public final class ViewRootImpl implements ViewParent,
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
- int resizeMode) {
+ boolean dragResizing) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState,
- forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, resizeMode);
+ forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing);
}
}
@@ -10451,13 +10448,13 @@ public final class ViewRootImpl implements ViewParent,
* Start a drag resizing which will inform all listeners that a window resize is taking place.
*/
private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets, int resizeMode) {
+ Rect stableInsets) {
if (!mDragResizing) {
mDragResizing = true;
if (mUseMTRenderer) {
for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
mWindowCallbacks.get(i).onWindowDragResizeStart(
- initialBounds, fullscreen, systemInsets, stableInsets, resizeMode);
+ initialBounds, fullscreen, systemInsets, stableInsets);
}
}
mFullRedrawNeeded = true;
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
index a7f0ef0a0324..94b2d93455d3 100644
--- a/core/java/android/view/WindowCallbacks.java
+++ b/core/java/android/view/WindowCallbacks.java
@@ -28,22 +28,6 @@ import android.graphics.Rect;
*/
public interface WindowCallbacks {
- int RESIZE_MODE_INVALID = -1;
-
- /**
- * The window is being resized by dragging one of the window corners,
- * in this case the surface would be fullscreen-sized. The client should
- * render to the actual frame location (instead of (0,curScrollY)).
- */
- int RESIZE_MODE_FREEFORM = 0;
-
- /**
- * The window is being resized by dragging on the docked divider. The client should render
- * at (0, 0) and extend its background to the background frame passed into
- * {@link IWindow#resized}.
- */
- int RESIZE_MODE_DOCKED_DIVIDER = 1;
-
/**
* Called by the system when the window got changed by the user, before the layouter got called.
* It also gets called when the insets changed, or when the window switched between a fullscreen
@@ -69,7 +53,7 @@ public interface WindowCallbacks {
* @param stableInsets The stable insets for the window.
*/
void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets, int resizeMode);
+ Rect stableInsets);
/**
* Called when a drag resize ends.
diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java
index 52e4e15cc9a0..141849f0593a 100644
--- a/core/java/android/view/WindowMetrics.java
+++ b/core/java/android/view/WindowMetrics.java
@@ -25,22 +25,64 @@ import android.graphics.Rect;
* <p>
* This is usually obtained from {@link WindowManager#getCurrentWindowMetrics()} and
* {@link WindowManager#getMaximumWindowMetrics()}.
+ * </p>
+ * After {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, it also provides density.
+ * <h3>Obtains Window Dimensions in Density-independent Pixel(DP)</h3>
+ * <p>
+ * While {@link #getDensity()} is provided, the dimension in density-independent pixel could also be
+ * calculated with {@code WindowMetrics} properties, which is similar to
+ * {@link android.content.res.Configuration#screenWidthDp}
+ * <pre class="prettyprint">
+ * float widthInDp = windowMetrics.getBounds().width() / windowMetrics.getDensity();
+ * float heightInDp = windowMetrics.getBounds().height() / windowMetrics.getDensity();
+ * </pre>
+ * Also, the density in DPI can be obtained by:
+ * <pre class="prettyprint">
+ * float densityDp = DisplayMetrics.DENSITY_DEFAULT * windowMetrics.getDensity();
+ * </pre>
+ * </p>
*
* @see WindowInsets#getInsets(int)
* @see WindowManager#getCurrentWindowMetrics()
* @see WindowManager#getMaximumWindowMetrics()
+ * @see android.annotation.UiContext
*/
public final class WindowMetrics {
- private final @NonNull Rect mBounds;
- private final @NonNull WindowInsets mWindowInsets;
+ @NonNull
+ private final Rect mBounds;
+ @NonNull
+ private final WindowInsets mWindowInsets;
+
+ /** @see android.util.DisplayMetrics#density */
+ private final float mDensity;
+ /** @deprecated use {@link #WindowMetrics(Rect, WindowInsets, float)} instead. */
+ @Deprecated
public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets) {
+ this(bounds, windowInsets, 1.0f);
+ }
+
+ /**
+ * The constructor to create a {@link WindowMetrics} instance.
+ * <p>
+ * Note that in most cases {@link WindowMetrics} is obtained from
+ * {@link WindowManager#getCurrentWindowMetrics()} or
+ * {@link WindowManager#getMaximumWindowMetrics()}.
+ * </p>
+ *
+ * @param bounds The window bounds
+ * @param windowInsets The {@link WindowInsets} of the window
+ * @param density The window density
+ */
+ public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets, float density) {
mBounds = bounds;
mWindowInsets = windowInsets;
+ mDensity = density;
}
/**
- * Returns the bounds of the area associated with this window or visual context.
+ * Returns the bounds of the area associated with this window or
+ * {@link android.annotation.UiContext}.
* <p>
* <b>Note that the size of the reported bounds can have different size than
* {@link Display#getSize(Point)}.</b> This method reports the window size including all system
@@ -66,16 +108,40 @@ public final class WindowMetrics {
*
* @return window bounds in pixels.
*/
- public @NonNull Rect getBounds() {
+ @NonNull
+ public Rect getBounds() {
return mBounds;
}
/**
- * Returns the {@link WindowInsets} of the area associated with this window or visual context.
+ * Returns the {@link WindowInsets} of the area associated with this window or
+ * {@link android.annotation.UiContext}.
*
* @return the {@link WindowInsets} of the visual area.
*/
- public @NonNull WindowInsets getWindowInsets() {
+ @NonNull
+ public WindowInsets getWindowInsets() {
return mWindowInsets;
}
+
+ /**
+ * Returns the density of the area associated with this window or
+ * {@link android.annotation.UiContext}, which uses the same units as
+ * {@link android.util.DisplayMetrics#density}.
+ *
+ * @see android.util.DisplayMetrics#DENSITY_DEFAULT
+ * @see android.util.DisplayMetrics#density
+ */
+ public float getDensity() {
+ return mDensity;
+ }
+
+ @Override
+ public String toString() {
+ return WindowMetrics.class.getSimpleName() + ":{"
+ + "bounds=" + mBounds
+ + ", windowInsets=" + mWindowInsets
+ + ", density" + mDensity
+ + "}";
+ }
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 69340aa39daf..2d6c1d913e90 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.view.WindowCallbacks.RESIZE_MODE_INVALID;
-
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -550,7 +548,7 @@ public class WindowlessWindowManager implements IWindowSession {
mTmpConfig.setConfiguration(mConfiguration, mConfiguration);
s.mClient.resized(mTmpFrames, false /* reportDraw */, mTmpConfig, state,
false /* forceLayout */, false /* alwaysConsumeSystemBars */, s.mDisplayId,
- Integer.MAX_VALUE, RESIZE_MODE_INVALID);
+ Integer.MAX_VALUE, false /* dragResizing */);
} catch (RemoteException e) {
// Too bad
}
diff --git a/core/java/android/window/TaskConstants.java b/core/java/android/window/TaskConstants.java
new file mode 100644
index 000000000000..c40384027adf
--- /dev/null
+++ b/core/java/android/window/TaskConstants.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.window;
+
+import android.annotation.IntDef;
+
+/**
+ * Holds constants related to task managements but not suitable in {@code TaskOrganizer}.
+ * @hide
+ */
+public class TaskConstants {
+
+ /**
+ * Sizes of a z-order region assigned to child layers of task layers. Components are allowed to
+ * use all values in [assigned value, assigned value + region size).
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_REGION_SIZE = 10000;
+
+ /**
+ * Indicates system responding to task drag resizing while app content isn't updated.
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_TASK_BACKGROUND = -3 * TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * Provides solid color letterbox background or blur effect and dimming for the wallpaper
+ * letterbox background. It also listens to touches for double tap gesture for repositioning
+ * letterbox.
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_LETTERBOX_BACKGROUND =
+ -2 * TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * When a unresizable app is moved in the different configuration, a restart button appears
+ * allowing to adapt (~resize) app to the new configuration mocks.
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_SIZE_COMPAT_RESTART_BUTTON =
+ TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * Shown the first time an app is opened in size compat mode in landscape.
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_LETTERBOX_EDUCATION = 2 * TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * Captions, window frames and resize handlers around task windows.
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_WINDOW_DECORATIONS = 3 * TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * Overlays the task when going into PIP w/ gesture navigation.
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_RECENTS_ANIMATION_PIP_OVERLAY =
+ 4 * TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * Allows other apps to add overlays on the task (i.e. game dashboard)
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_TASK_OVERLAY = 5 * TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * Legacy machanism to force an activity to the top of the task (i.e. for work profile
+ * comfirmation).
+ * @hide
+ */
+ public static final int TASK_CHILD_LAYER_TASK_OVERLAY_ACTIVITIES =
+ 6 * TASK_CHILD_LAYER_REGION_SIZE;
+
+ /**
+ * Z-orders of task child layers other than activities, task fragments and layers interleaved
+ * with them, e.g. IME windows. [-10000, 10000) is reserved for these layers.
+ * @hide
+ */
+ @IntDef({
+ TASK_CHILD_LAYER_TASK_BACKGROUND,
+ TASK_CHILD_LAYER_LETTERBOX_BACKGROUND,
+ TASK_CHILD_LAYER_SIZE_COMPAT_RESTART_BUTTON,
+ TASK_CHILD_LAYER_LETTERBOX_EDUCATION,
+ TASK_CHILD_LAYER_WINDOW_DECORATIONS,
+ TASK_CHILD_LAYER_RECENTS_ANIMATION_PIP_OVERLAY,
+ TASK_CHILD_LAYER_TASK_OVERLAY,
+ TASK_CHILD_LAYER_TASK_OVERLAY_ACTIVITIES
+ })
+ public @interface TaskChildLayer {}
+}
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index ef19c55019dc..283df7608806 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -20,22 +20,20 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import android.annotation.CallSuper;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
-import android.app.WindowConfiguration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
-import java.util.List;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
/**
@@ -63,6 +61,52 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";
/**
+ * No change set.
+ */
+ @WindowManager.TransitionType
+ @TaskFragmentTransitionType
+ public static final int TASK_FRAGMENT_TRANSIT_NONE = TRANSIT_NONE;
+
+ /**
+ * A window that didn't exist before has been created and made visible.
+ */
+ @WindowManager.TransitionType
+ @TaskFragmentTransitionType
+ public static final int TASK_FRAGMENT_TRANSIT_OPEN = TRANSIT_OPEN;
+
+ /**
+ * A window that was visible no-longer exists (was finished or destroyed).
+ */
+ @WindowManager.TransitionType
+ @TaskFragmentTransitionType
+ public static final int TASK_FRAGMENT_TRANSIT_CLOSE = TRANSIT_CLOSE;
+
+ /**
+ * A window is visible before and after but changes in some way (eg. it resizes or changes
+ * windowing-mode).
+ */
+ @WindowManager.TransitionType
+ @TaskFragmentTransitionType
+ public static final int TASK_FRAGMENT_TRANSIT_CHANGE = TRANSIT_CHANGE;
+
+ /**
+ * Introduced a sub set of {@link WindowManager.TransitionType} for the types that are used for
+ * TaskFragment transition.
+ *
+ * Doing this instead of exposing {@link WindowManager.TransitionType} because we want to keep
+ * the Shell transition API hidden until it comes fully stable.
+ * @hide
+ */
+ @IntDef(prefix = { "TASK_FRAGMENT_TRANSIT_" }, value = {
+ TASK_FRAGMENT_TRANSIT_NONE,
+ TASK_FRAGMENT_TRANSIT_OPEN,
+ TASK_FRAGMENT_TRANSIT_CLOSE,
+ TASK_FRAGMENT_TRANSIT_CHANGE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TaskFragmentTransitionType {}
+
+ /**
* Creates a {@link Bundle} with an exception, operation type and TaskFragmentInfo (if any)
* that can be passed to {@link ITaskFragmentOrganizer#onTaskFragmentError}.
* @hide
@@ -155,7 +199,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* {@link #onTransactionReady(TaskFragmentTransaction)}
* @param wct {@link WindowContainerTransaction} that the server should apply for
* update of the transaction.
- * @param transitionType {@link WindowManager.TransitionType} if it needs to start a
+ * @param transitionType {@link TaskFragmentTransitionType} if it needs to start a
* transition.
* @param shouldApplyIndependently If {@code true}, the {@code wct} will request a new
* transition, which will be queued until the sync engine is
@@ -163,11 +207,10 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* the {@code wct} will be directly applied to the active sync.
* @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission
* for permission enforcement.
- * @hide
*/
public void onTransactionHandled(@NonNull IBinder transactionToken,
@NonNull WindowContainerTransaction wct,
- @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
+ @TaskFragmentTransitionType int transitionType, boolean shouldApplyIndependently) {
wct.setTaskFragmentOrganizer(mInterface);
try {
getController().onTransactionHandled(transactionToken, wct, transitionType,
@@ -178,22 +221,19 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
}
/**
- * Routes to {@link ITaskFragmentOrganizerController#applyTransaction} instead of
- * {@link IWindowOrganizerController#applyTransaction} for the different transition options.
- *
+ * Must use {@link #applyTransaction(WindowContainerTransaction, int, boolean)} instead.
* @see #applyTransaction(WindowContainerTransaction, int, boolean)
*/
@Override
public void applyTransaction(@NonNull WindowContainerTransaction wct) {
- // TODO(b/207070762) doing so to keep CTS compatibility. Remove in the next release.
- applyTransaction(wct, getTransitionType(wct), false /* shouldApplyIndependently */);
+ throw new RuntimeException("Not allowed!");
}
/**
* Requests the server to apply the given {@link WindowContainerTransaction}.
*
* @param wct {@link WindowContainerTransaction} to apply.
- * @param transitionType {@link WindowManager.TransitionType} if it needs to start a
+ * @param transitionType {@link TaskFragmentTransitionType} if it needs to start a
* transition.
* @param shouldApplyIndependently If {@code true}, the {@code wct} will request a new
* transition, which will be queued until the sync engine is
@@ -201,10 +241,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* the {@code wct} will be directly applied to the active sync.
* @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission
* for permission enforcement.
- * @hide
*/
public void applyTransaction(@NonNull WindowContainerTransaction wct,
- @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
+ @TaskFragmentTransitionType int transitionType, boolean shouldApplyIndependently) {
if (wct.isEmpty()) {
return;
}
@@ -217,56 +256,13 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
}
/**
- * Gets the default {@link WindowManager.TransitionType} based on the requested
- * {@link WindowContainerTransaction}.
- * @hide
- */
- // TODO(b/207070762): let Extensions to set the transition type instead.
- @WindowManager.TransitionType
- public static int getTransitionType(@NonNull WindowContainerTransaction wct) {
- if (wct.isEmpty()) {
- return TRANSIT_NONE;
- }
- for (WindowContainerTransaction.Change change : wct.getChanges().values()) {
- if ((change.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) {
- // Treat as TRANSIT_CHANGE when there is TaskFragment resizing.
- return TRANSIT_CHANGE;
- }
- }
- boolean containsCreatingTaskFragment = false;
- boolean containsDeleteTaskFragment = false;
- final List<WindowContainerTransaction.HierarchyOp> ops = wct.getHierarchyOps();
- for (int i = ops.size() - 1; i >= 0; i--) {
- final int type = ops.get(i).getType();
- if (type == HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT) {
- // Treat as TRANSIT_CHANGE when there is activity reparent.
- return TRANSIT_CHANGE;
- }
- if (type == HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT) {
- containsCreatingTaskFragment = true;
- } else if (type == HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT) {
- containsDeleteTaskFragment = true;
- }
- }
- if (containsCreatingTaskFragment) {
- return TRANSIT_OPEN;
- }
- if (containsDeleteTaskFragment) {
- return TRANSIT_CLOSE;
- }
-
- // Use TRANSIT_CHANGE as default.
- return TRANSIT_CHANGE;
- }
-
- /**
* Called when the transaction is ready so that the organizer can update the TaskFragments based
* on the changes in transaction.
*/
public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
// Notify the server to finish the transaction.
onTransactionHandled(transaction.getTransactionToken(), new WindowContainerTransaction(),
- TRANSIT_NONE, false /* shouldApplyIndependently */);
+ TASK_FRAGMENT_TRANSIT_NONE, false /* shouldApplyIndependently */);
}
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index 930aaa2b291b..695d01e92316 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -40,14 +40,11 @@ public class WindowOrganizer {
* Apply multiple WindowContainer operations at once.
*
* Note that using this API requires the caller to hold
- * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using
- * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is
- * created by itself.
+ * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}.
*
* @param t The transaction to apply.
*/
- @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
- conditional = true)
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
public void applyTransaction(@NonNull WindowContainerTransaction t) {
try {
if (!t.isEmpty()) {
@@ -62,9 +59,7 @@ public class WindowOrganizer {
* Apply multiple WindowContainer operations at once.
*
* Note that using this API requires the caller to hold
- * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using
- * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is
- * created by itself.
+ * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}.
*
* @param t The transaction to apply.
* @param callback This transaction will use the synchronization scheme described in
@@ -73,8 +68,7 @@ public class WindowOrganizer {
* @return An ID for the sync operation which will later be passed to transactionReady callback.
* This lets the caller differentiate overlapping sync operations.
*/
- @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
- conditional = true)
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
public int applySyncTransaction(@NonNull WindowContainerTransaction t,
@NonNull WindowContainerTransactionCallback callback) {
try {
diff --git a/core/java/com/android/internal/inputmethod/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java
index f101497125e9..7dbbffda49ba 100644
--- a/core/java/com/android/internal/inputmethod/InputBindResult.java
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.java
@@ -170,6 +170,9 @@ public final class InputBindResult implements Parcelable {
* display.
*/
int ERROR_INVALID_DISPLAY_ID = 15;
+ /**
+ * Indicates that a valid session is created and result is ready for accessibility.
+ */
int SUCCESS_WITH_ACCESSIBILITY_SESSION = 16;
}
@@ -389,6 +392,8 @@ public final class InputBindResult implements Parcelable {
return "ERROR_DISPLAY_ID_MISMATCH";
case ResultCode.ERROR_INVALID_DISPLAY_ID:
return "ERROR_INVALID_DISPLAY_ID";
+ case ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION:
+ return "SUCCESS_WITH_ACCESSIBILITY_SESSION";
default:
return "Unknown(" + result + ")";
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 75f0bf574947..7bd6ec8f0f2c 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -780,17 +780,17 @@ public class InteractionJankMonitor {
// 2. The returned string should be the same with the name defined in atoms.proto.
switch (cujType) {
case CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE:
- return "SHADE_EXPAND_COLLAPSE";
+ return "NOTIFICATION_SHADE_EXPAND_COLLAPSE";
case CUJ_NOTIFICATION_SHADE_SCROLL_FLING:
- return "SHADE_SCROLL_FLING";
+ return "NOTIFICATION_SHADE_SCROLL_FLING";
case CUJ_NOTIFICATION_SHADE_ROW_EXPAND:
- return "SHADE_ROW_EXPAND";
+ return "NOTIFICATION_SHADE_ROW_EXPAND";
case CUJ_NOTIFICATION_SHADE_ROW_SWIPE:
- return "SHADE_ROW_SWIPE";
+ return "NOTIFICATION_SHADE_ROW_SWIPE";
case CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE:
- return "SHADE_QS_EXPAND_COLLAPSE";
+ return "NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE";
case CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE:
- return "SHADE_QS_SCROLL_SWIPE";
+ return "NOTIFICATION_SHADE_QS_SCROLL_SWIPE";
case CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS:
return "LAUNCHER_APP_LAUNCH_FROM_RECENTS";
case CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON:
@@ -880,9 +880,9 @@ public class InteractionJankMonitor {
case CUJ_SPLIT_SCREEN_EXIT:
return "SPLIT_SCREEN_EXIT";
case CUJ_LOCKSCREEN_LAUNCH_CAMERA:
- return "CUJ_LOCKSCREEN_LAUNCH_CAMERA";
+ return "LOCKSCREEN_LAUNCH_CAMERA";
case CUJ_SPLIT_SCREEN_RESIZE:
- return "CUJ_SPLIT_SCREEN_RESIZE";
+ return "SPLIT_SCREEN_RESIZE";
case CUJ_SETTINGS_SLIDER:
return "SETTINGS_SLIDER";
case CUJ_TAKE_SCREENSHOT:
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 145aeafb46a1..b5b27f5289c9 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -274,7 +274,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private boolean mApplyFloatingVerticalInsets = false;
private boolean mApplyFloatingHorizontalInsets = false;
- private int mResizeMode = RESIZE_MODE_INVALID;
private final int mResizeShadowSize;
private final Paint mVerticalResizeShadowPaint = new Paint();
private final Paint mHorizontalResizeShadowPaint = new Paint();
@@ -808,9 +807,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
updateElevation();
mAllowUpdateElevation = true;
- if (changed
- && (mResizeMode == RESIZE_MODE_DOCKED_DIVIDER
- || mDrawLegacyNavigationBarBackground)) {
+ if (changed && mDrawLegacyNavigationBarBackground) {
getViewRootImpl().requestInvalidateRootRenderNode();
}
}
@@ -2392,7 +2389,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
@Override
public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets, int resizeMode) {
+ Rect stableInsets) {
if (mWindow.isDestroyed()) {
// If the owner's window is gone, we should not be able to come here anymore.
releaseThreadedRenderer();
@@ -2418,7 +2415,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
updateColorViews(null /* insets */, false);
}
- mResizeMode = resizeMode;
getViewRootImpl().requestInvalidateRootRenderNode();
}
@@ -2426,7 +2422,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
public void onWindowDragResizeEnd() {
releaseThreadedRenderer();
updateColorViews(null /* insets */, false);
- mResizeMode = RESIZE_MODE_INVALID;
getViewRootImpl().requestInvalidateRootRenderNode();
}
@@ -2471,9 +2466,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
private void drawResizingShadowIfNeeded(RecordingCanvas canvas) {
- if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
- || mWindow.isTranslucent()
- || mWindow.isShowingWallpaper()) {
+ if (mWindow.mIsFloating || mWindow.isTranslucent() || mWindow.isShowingWallpaper()) {
return;
}
canvas.save();
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 2ac43099c741..4a5ed7e8970d 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -53,7 +53,7 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing) {
if (reportDraw) {
try {
mSession.finishDrawing(this, null /* postDrawTransaction */, seqId);
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 365a18d174c9..a8abe50a9755 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -529,9 +529,8 @@ static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz
return Camera::getNumberOfCameras();
}
-static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz,
- jint cameraId, jobject info_obj)
-{
+static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jint cameraId,
+ jboolean overrideToPortrait, jobject info_obj) {
CameraInfo cameraInfo;
if (cameraId >= Camera::getNumberOfCameras() || cameraId < 0) {
ALOGE("%s: Unknown camera ID %d", __FUNCTION__, cameraId);
@@ -539,7 +538,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz,
return;
}
- status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
+ status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, &cameraInfo);
if (rc != NO_ERROR) {
jniThrowRuntimeException(env, "Fail to get camera info");
return;
@@ -555,9 +554,9 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz,
}
// connect to camera service
-static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
- jobject weak_this, jint cameraId, jstring clientPackageName)
-{
+static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+ jint cameraId, jstring clientPackageName,
+ jboolean overrideToPortrait) {
// Convert jstring to String16
const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
env->GetStringChars(clientPackageName, NULL));
@@ -567,8 +566,9 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
reinterpret_cast<const jchar*>(rawClientName));
int targetSdkVersion = android_get_application_target_sdk_version();
- sp<Camera> camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID,
- Camera::USE_CALLING_PID, targetSdkVersion);
+ sp<Camera> camera =
+ Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID,
+ targetSdkVersion, overrideToPortrait);
if (camera == NULL) {
return -EACCES;
}
@@ -596,7 +596,7 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
// Update default display orientation in case the sensor is reverse-landscape
CameraInfo cameraInfo;
- status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
+ status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, &cameraInfo);
if (rc != NO_ERROR) {
ALOGE("%s: getCameraInfo error: %d", __FUNCTION__, rc);
return rc;
@@ -1051,93 +1051,43 @@ static int32_t android_hardware_Camera_getAudioRestriction(
//-------------------------------------------------
static const JNINativeMethod camMethods[] = {
- { "getNumberOfCameras",
- "()I",
- (void *)android_hardware_Camera_getNumberOfCameras },
- { "_getCameraInfo",
- "(ILandroid/hardware/Camera$CameraInfo;)V",
- (void*)android_hardware_Camera_getCameraInfo },
- { "native_setup",
- "(Ljava/lang/Object;ILjava/lang/String;)I",
- (void*)android_hardware_Camera_native_setup },
- { "native_release",
- "()V",
- (void*)android_hardware_Camera_release },
- { "setPreviewSurface",
- "(Landroid/view/Surface;)V",
- (void *)android_hardware_Camera_setPreviewSurface },
- { "setPreviewTexture",
- "(Landroid/graphics/SurfaceTexture;)V",
- (void *)android_hardware_Camera_setPreviewTexture },
- { "setPreviewCallbackSurface",
- "(Landroid/view/Surface;)V",
- (void *)android_hardware_Camera_setPreviewCallbackSurface },
- { "startPreview",
- "()V",
- (void *)android_hardware_Camera_startPreview },
- { "_stopPreview",
- "()V",
- (void *)android_hardware_Camera_stopPreview },
- { "previewEnabled",
- "()Z",
- (void *)android_hardware_Camera_previewEnabled },
- { "setHasPreviewCallback",
- "(ZZ)V",
- (void *)android_hardware_Camera_setHasPreviewCallback },
- { "_addCallbackBuffer",
- "([BI)V",
- (void *)android_hardware_Camera_addCallbackBuffer },
- { "native_autoFocus",
- "()V",
- (void *)android_hardware_Camera_autoFocus },
- { "native_cancelAutoFocus",
- "()V",
- (void *)android_hardware_Camera_cancelAutoFocus },
- { "native_takePicture",
- "(I)V",
- (void *)android_hardware_Camera_takePicture },
- { "native_setParameters",
- "(Ljava/lang/String;)V",
- (void *)android_hardware_Camera_setParameters },
- { "native_getParameters",
- "()Ljava/lang/String;",
- (void *)android_hardware_Camera_getParameters },
- { "reconnect",
- "()V",
- (void*)android_hardware_Camera_reconnect },
- { "lock",
- "()V",
- (void*)android_hardware_Camera_lock },
- { "unlock",
- "()V",
- (void*)android_hardware_Camera_unlock },
- { "startSmoothZoom",
- "(I)V",
- (void *)android_hardware_Camera_startSmoothZoom },
- { "stopSmoothZoom",
- "()V",
- (void *)android_hardware_Camera_stopSmoothZoom },
- { "setDisplayOrientation",
- "(I)V",
- (void *)android_hardware_Camera_setDisplayOrientation },
- { "_enableShutterSound",
- "(Z)Z",
- (void *)android_hardware_Camera_enableShutterSound },
- { "_startFaceDetection",
- "(I)V",
- (void *)android_hardware_Camera_startFaceDetection },
- { "_stopFaceDetection",
- "()V",
- (void *)android_hardware_Camera_stopFaceDetection},
- { "enableFocusMoveCallback",
- "(I)V",
- (void *)android_hardware_Camera_enableFocusMoveCallback},
- { "setAudioRestriction",
- "(I)V",
- (void *)android_hardware_Camera_setAudioRestriction},
- { "getAudioRestriction",
- "()I",
- (void *)android_hardware_Camera_getAudioRestriction},
+ {"getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras},
+ {"_getCameraInfo", "(IZLandroid/hardware/Camera$CameraInfo;)V",
+ (void *)android_hardware_Camera_getCameraInfo},
+ {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;Z)I",
+ (void *)android_hardware_Camera_native_setup},
+ {"native_release", "()V", (void *)android_hardware_Camera_release},
+ {"setPreviewSurface", "(Landroid/view/Surface;)V",
+ (void *)android_hardware_Camera_setPreviewSurface},
+ {"setPreviewTexture", "(Landroid/graphics/SurfaceTexture;)V",
+ (void *)android_hardware_Camera_setPreviewTexture},
+ {"setPreviewCallbackSurface", "(Landroid/view/Surface;)V",
+ (void *)android_hardware_Camera_setPreviewCallbackSurface},
+ {"startPreview", "()V", (void *)android_hardware_Camera_startPreview},
+ {"_stopPreview", "()V", (void *)android_hardware_Camera_stopPreview},
+ {"previewEnabled", "()Z", (void *)android_hardware_Camera_previewEnabled},
+ {"setHasPreviewCallback", "(ZZ)V", (void *)android_hardware_Camera_setHasPreviewCallback},
+ {"_addCallbackBuffer", "([BI)V", (void *)android_hardware_Camera_addCallbackBuffer},
+ {"native_autoFocus", "()V", (void *)android_hardware_Camera_autoFocus},
+ {"native_cancelAutoFocus", "()V", (void *)android_hardware_Camera_cancelAutoFocus},
+ {"native_takePicture", "(I)V", (void *)android_hardware_Camera_takePicture},
+ {"native_setParameters", "(Ljava/lang/String;)V",
+ (void *)android_hardware_Camera_setParameters},
+ {"native_getParameters", "()Ljava/lang/String;",
+ (void *)android_hardware_Camera_getParameters},
+ {"reconnect", "()V", (void *)android_hardware_Camera_reconnect},
+ {"lock", "()V", (void *)android_hardware_Camera_lock},
+ {"unlock", "()V", (void *)android_hardware_Camera_unlock},
+ {"startSmoothZoom", "(I)V", (void *)android_hardware_Camera_startSmoothZoom},
+ {"stopSmoothZoom", "()V", (void *)android_hardware_Camera_stopSmoothZoom},
+ {"setDisplayOrientation", "(I)V", (void *)android_hardware_Camera_setDisplayOrientation},
+ {"_enableShutterSound", "(Z)Z", (void *)android_hardware_Camera_enableShutterSound},
+ {"_startFaceDetection", "(I)V", (void *)android_hardware_Camera_startFaceDetection},
+ {"_stopFaceDetection", "()V", (void *)android_hardware_Camera_stopFaceDetection},
+ {"enableFocusMoveCallback", "(I)V",
+ (void *)android_hardware_Camera_enableFocusMoveCallback},
+ {"setAudioRestriction", "(I)V", (void *)android_hardware_Camera_setAudioRestriction},
+ {"getAudioRestriction", "()I", (void *)android_hardware_Camera_getAudioRestriction},
};
struct field {
diff --git a/core/jni/android_media_AudioMixerAttributes.h b/core/jni/android_media_AudioMixerAttributes.h
new file mode 100644
index 000000000000..9e4637f3cb61
--- /dev/null
+++ b/core/jni/android_media_AudioMixerAttributes.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIOMIXERATTRIBUTES_H
+#define ANDROID_MEDIA_AUDIOMIXERATTRIBUTES_H
+
+#include <system/audio.h>
+
+// Keep sync with AudioMixerAttributes.java
+#define MIXER_BEHAVIOR_DEFAULT 0
+#define MIXER_BEHAVIOR_BIT_PERFECT 1
+// Invalid value is not added in JAVA API, but keep sync with native value
+#define MIXER_BEHAVIOR_INVALID -1
+
+static inline audio_mixer_behavior_t audioMixerBehaviorToNative(int mixerBehavior) {
+ switch (mixerBehavior) {
+ case MIXER_BEHAVIOR_DEFAULT:
+ return AUDIO_MIXER_BEHAVIOR_DEFAULT;
+ case MIXER_BEHAVIOR_BIT_PERFECT:
+ return AUDIO_MIXER_BEHAVIOR_BIT_PERFECT;
+ default:
+ return AUDIO_MIXER_BEHAVIOR_INVALID;
+ }
+}
+
+static inline jint audioMixerBehaviorFromNative(audio_mixer_behavior_t mixerBehavior) {
+ switch (mixerBehavior) {
+ case AUDIO_MIXER_BEHAVIOR_DEFAULT:
+ return MIXER_BEHAVIOR_DEFAULT;
+ case AUDIO_MIXER_BEHAVIOR_BIT_PERFECT:
+ return MIXER_BEHAVIOR_BIT_PERFECT;
+ case AUDIO_MIXER_BEHAVIOR_INVALID:
+ default:
+ return MIXER_BEHAVIOR_INVALID;
+ }
+}
+
+#endif
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 334a0e0fd0a1..28ac464bdf72 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -21,6 +21,7 @@
#include <android/media/AudioVibratorInfo.h>
#include <android/media/INativeSpatializerCallback.h>
#include <android/media/ISpatializer.h>
+#include <android/media/audio/common/AudioConfigBase.h>
#include <android_os_Parcel.h>
#include <audiomanager/AudioManager.h>
#include <jni.h>
@@ -34,6 +35,7 @@
#include <system/audio_policy.h>
#include <utils/Log.h>
+#include <optional>
#include <sstream>
#include <vector>
@@ -43,6 +45,7 @@
#include "android_media_AudioEffectDescriptor.h"
#include "android_media_AudioErrors.h"
#include "android_media_AudioFormat.h"
+#include "android_media_AudioMixerAttributes.h"
#include "android_media_AudioProfile.h"
#include "android_media_MicrophoneInfo.h"
#include "android_util_Binder.h"
@@ -51,6 +54,7 @@
// ----------------------------------------------------------------------------
using namespace android;
+using media::audio::common::AudioConfigBase;
static const char* const kClassPathName = "android/media/AudioSystem";
@@ -145,10 +149,12 @@ static struct {
} gAudioMixFields;
static jclass gAudioFormatClass;
+static jmethodID gAudioFormatCstor;
static struct {
jfieldID mEncoding;
jfieldID mSampleRate;
jfieldID mChannelMask;
+ jfieldID mChannelIndexMask;
// other fields unused by JNI
} gAudioFormatFields;
@@ -211,6 +217,7 @@ static struct {
jfieldID mChannelMasks;
jfieldID mChannelIndexMasks;
jfieldID mEncapsulationType;
+ jfieldID mMixerBehaviors;
} gAudioProfileFields;
jclass gVibratorClass;
@@ -221,6 +228,13 @@ static struct {
jmethodID getMaxAmplitude;
} gVibratorMethods;
+jclass gAudioMixerAttributesClass;
+jmethodID gAudioMixerAttributesCstor;
+static struct {
+ jfieldID mFormat;
+ jfieldID mMixerBehavior;
+} gAudioMixerAttributesField;
+
static Mutex gLock;
enum AudioError {
@@ -237,6 +251,12 @@ enum {
#define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
+// Keep sync with AudioFormat.java
+#define AUDIO_FORMAT_HAS_PROPERTY_ENCODING 0x1
+#define AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE 0x2
+#define AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK 0x4
+#define AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK 0x8
+
// ----------------------------------------------------------------------------
// ref-counted object for audio port callbacks
class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
@@ -2105,6 +2125,80 @@ void javaAudioFormatToNativeAudioConfig(JNIEnv *env, audio_config_t *nConfig,
}
}
+void javaAudioFormatToNativeAudioConfigBase(JNIEnv *env, const jobject jFormat,
+ audio_config_base_t *nConfigBase, bool isInput) {
+ *nConfigBase = AUDIO_CONFIG_BASE_INITIALIZER;
+ nConfigBase->format =
+ audioFormatToNative(env->GetIntField(jFormat, gAudioFormatFields.mEncoding));
+ nConfigBase->sample_rate = env->GetIntField(jFormat, gAudioFormatFields.mSampleRate);
+ jint jChannelMask = env->GetIntField(jFormat, gAudioFormatFields.mChannelMask);
+ jint jChannelIndexMask = env->GetIntField(jFormat, gAudioFormatFields.mChannelIndexMask);
+ nConfigBase->channel_mask = jChannelIndexMask != 0
+ ? audio_channel_mask_from_representation_and_bits(AUDIO_CHANNEL_REPRESENTATION_INDEX,
+ jChannelIndexMask)
+ : isInput ? inChannelMaskToNative(jChannelMask)
+ : outChannelMaskToNative(jChannelMask);
+}
+
+jobject nativeAudioConfigBaseToJavaAudioFormat(JNIEnv *env, const audio_config_base_t *nConfigBase,
+ bool isInput) {
+ if (nConfigBase == nullptr) {
+ return nullptr;
+ }
+ int propertyMask = AUDIO_FORMAT_HAS_PROPERTY_ENCODING | AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE;
+ int channelMask = 0;
+ int channelIndexMask = 0;
+ switch (audio_channel_mask_get_representation(nConfigBase->channel_mask)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ channelMask = isInput ? inChannelMaskFromNative(nConfigBase->channel_mask)
+ : outChannelMaskFromNative(nConfigBase->channel_mask);
+ propertyMask |= AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK;
+ break;
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ channelIndexMask = audio_channel_mask_get_bits(nConfigBase->channel_mask);
+ propertyMask |= AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK;
+ break;
+ default:
+ // This must not happen
+ break;
+ }
+ return env->NewObject(gAudioFormatClass, gAudioFormatCstor, propertyMask,
+ audioFormatFromNative(nConfigBase->format), nConfigBase->sample_rate,
+ channelMask, channelIndexMask);
+}
+
+jint convertAudioMixerAttributesToNative(JNIEnv *env, const jobject jAudioMixerAttributes,
+ audio_mixer_attributes_t *nMixerAttributes) {
+ ScopedLocalRef<jobject> jFormat(env,
+ env->GetObjectField(jAudioMixerAttributes,
+ gAudioMixerAttributesField.mFormat));
+ javaAudioFormatToNativeAudioConfigBase(env, jFormat.get(), &nMixerAttributes->config,
+ false /*isInput*/);
+ nMixerAttributes->mixer_behavior = audioMixerBehaviorToNative(
+ env->GetIntField(jAudioMixerAttributes, gAudioMixerAttributesField.mMixerBehavior));
+ if (nMixerAttributes->mixer_behavior == AUDIO_MIXER_BEHAVIOR_INVALID) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ return (jint)AUDIO_JAVA_SUCCESS;
+}
+
+jobject convertAudioMixerAttributesFromNative(JNIEnv *env,
+ const audio_mixer_attributes_t *nMixerAttributes) {
+ if (nMixerAttributes == nullptr) {
+ return nullptr;
+ }
+ jint mixerBehavior = audioMixerBehaviorFromNative(nMixerAttributes->mixer_behavior);
+ if (mixerBehavior == MIXER_BEHAVIOR_INVALID) {
+ return nullptr;
+ }
+ ScopedLocalRef<jobject>
+ jFormat(env,
+ nativeAudioConfigBaseToJavaAudioFormat(env, &nMixerAttributes->config,
+ false /*isInput*/));
+ return env->NewObject(gAudioMixerAttributesClass, gAudioMixerAttributesCstor, jFormat.get(),
+ mixerBehavior);
+}
+
static jint convertAudioMixToNative(JNIEnv *env,
AudioMix *nAudioMix,
const jobject jAudioMix)
@@ -2868,13 +2962,18 @@ static jboolean android_media_AudioSystem_canBeSpatialized(JNIEnv *env, jobject
return canBeSpatialized;
}
-static jint android_media_AudioSystem_registerSoundDoseCallback(JNIEnv *env, jobject thiz,
- jobject jISoundDoseCallback) {
+static jobject android_media_AudioSystem_nativeGetSoundDose(JNIEnv *env, jobject thiz,
+ jobject jISoundDoseCallback) {
sp<media::ISoundDoseCallback> nISoundDoseCallback = interface_cast<media::ISoundDoseCallback>(
ibinderForJavaObject(env, jISoundDoseCallback));
- return static_cast<jint>(
- check_AudioSystem_Command(AudioSystem::registerSoundDoseCallback(nISoundDoseCallback)));
+ sp<media::ISoundDose> nSoundDose;
+ status_t status = AudioSystem::getSoundDoseInterface(nISoundDoseCallback, &nSoundDose);
+
+ if (status != NO_ERROR) {
+ return nullptr;
+ }
+ return javaObjectForIBinder(env, IInterface::asBinder(nSoundDose));
}
// keep these values in sync with AudioSystem.java
@@ -2966,6 +3065,142 @@ static jint android_media_AudioSystem_getDirectProfilesForAttributes(JNIEnv *env
return jStatus;
}
+static jint android_media_AudioSystem_getSupportedMixerAttributes(JNIEnv *env, jobject thiz,
+ jint jDeviceId,
+ jobject jAudioMixerAttributes) {
+ ALOGV("%s", __func__);
+ if (jAudioMixerAttributes == NULL) {
+ ALOGE("getSupportedMixerAttributes NULL AudioMixerAttributes list");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jAudioMixerAttributes, gListClass)) {
+ ALOGE("getSupportedMixerAttributes not a list");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ std::vector<audio_mixer_attributes_t> nMixerAttributes;
+ status_t status = AudioSystem::getSupportedMixerAttributes((audio_port_handle_t)jDeviceId,
+ &nMixerAttributes);
+ if (status != NO_ERROR) {
+ return nativeToJavaStatus(status);
+ }
+ for (const auto &mixerAttr : nMixerAttributes) {
+ ScopedLocalRef<jobject> jMixerAttributes(env,
+ convertAudioMixerAttributesFromNative(env,
+ &mixerAttr));
+ if (jMixerAttributes.get() == nullptr) {
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+
+ env->CallBooleanMethod(jAudioMixerAttributes, gListMethods.add, jMixerAttributes.get());
+ }
+
+ return (jint)AUDIO_JAVA_SUCCESS;
+}
+
+static jint android_media_AudioSystem_setPreferredMixerAttributes(JNIEnv *env, jobject thiz,
+ jobject jAudioAttributes,
+ jint portId, jint uid,
+ jobject jAudioMixerAttributes) {
+ ALOGV("%s", __func__);
+
+ if (jAudioAttributes == nullptr) {
+ ALOGE("jAudioAttributes is NULL");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ if (jAudioMixerAttributes == nullptr) {
+ ALOGE("jAudioMixerAttributes is NULL");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+
+ audio_mixer_attributes_t mixerAttributes = AUDIO_MIXER_ATTRIBUTES_INITIALIZER;
+ jStatus = convertAudioMixerAttributesToNative(env, jAudioMixerAttributes, &mixerAttributes);
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+
+ status_t status =
+ AudioSystem::setPreferredMixerAttributes(paa.get(), (audio_port_handle_t)portId,
+ (uid_t)uid, &mixerAttributes);
+ return nativeToJavaStatus(status);
+}
+
+static jint android_media_AudioSystem_getPreferredMixerAttributes(JNIEnv *env, jobject thiz,
+ jobject jAudioAttributes,
+ jint portId,
+ jobject jAudioMixerAttributes) {
+ ALOGV("%s", __func__);
+
+ if (jAudioAttributes == nullptr) {
+ ALOGE("getPreferredMixerAttributes jAudioAttributes is NULL");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ if (jAudioMixerAttributes == NULL) {
+ ALOGE("getPreferredMixerAttributes NULL AudioMixerAttributes list");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jAudioMixerAttributes, gListClass)) {
+ ALOGE("getPreferredMixerAttributes not a list");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+
+ std::optional<audio_mixer_attributes_t> nMixerAttributes;
+ status_t status =
+ AudioSystem::getPreferredMixerAttributes(paa.get(), (audio_port_handle_t)portId,
+ &nMixerAttributes);
+ if (status != NO_ERROR) {
+ return nativeToJavaStatus(status);
+ }
+
+ ScopedLocalRef<jobject>
+ jMixerAttributes(env,
+ convertAudioMixerAttributesFromNative(env,
+ nMixerAttributes.has_value()
+ ? &nMixerAttributes
+ .value()
+ : nullptr));
+ if (jMixerAttributes.get() == nullptr) {
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+
+ env->CallBooleanMethod(jAudioMixerAttributes, gListMethods.add, jMixerAttributes.get());
+ return AUDIO_JAVA_SUCCESS;
+}
+
+static jint android_media_AudioSystem_clearPreferredMixerAttributes(JNIEnv *env, jobject thiz,
+ jobject jAudioAttributes,
+ jint portId, jint uid) {
+ ALOGV("%s", __func__);
+
+ if (jAudioAttributes == nullptr) {
+ ALOGE("jAudioAttributes is NULL");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+
+ status_t status =
+ AudioSystem::clearPreferredMixerAttributes(paa.get(), (audio_port_handle_t)portId,
+ (uid_t)uid);
+ return nativeToJavaStatus(status);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] =
@@ -3113,14 +3348,23 @@ static const JNINativeMethod gMethods[] =
"(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
"[Landroid/media/AudioDeviceAttributes;)Z",
(void *)android_media_AudioSystem_canBeSpatialized},
- {"registerSoundDoseCallback", "(Landroid/media/ISoundDoseCallback;)I",
- (void *)android_media_AudioSystem_registerSoundDoseCallback},
+ {"nativeGetSoundDose", "(Landroid/media/ISoundDoseCallback;)Landroid/os/IBinder;",
+ (void *)android_media_AudioSystem_nativeGetSoundDose},
{"getDirectPlaybackSupport",
"(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
(void *)android_media_AudioSystem_getDirectPlaybackSupport},
{"getDirectProfilesForAttributes",
"(Landroid/media/AudioAttributes;Ljava/util/ArrayList;)I",
- (void *)android_media_AudioSystem_getDirectProfilesForAttributes}};
+ (void *)android_media_AudioSystem_getDirectProfilesForAttributes},
+ {"getSupportedMixerAttributes", "(ILjava/util/List;)I",
+ (void *)android_media_AudioSystem_getSupportedMixerAttributes},
+ {"setPreferredMixerAttributes",
+ "(Landroid/media/AudioAttributes;IILandroid/media/AudioMixerAttributes;)I",
+ (void *)android_media_AudioSystem_setPreferredMixerAttributes},
+ {"getPreferredMixerAttributes", "(Landroid/media/AudioAttributes;ILjava/util/List;)I",
+ (void *)android_media_AudioSystem_getPreferredMixerAttributes},
+ {"clearPreferredMixerAttributes", "(Landroid/media/AudioAttributes;II)I",
+ (void *)android_media_AudioSystem_clearPreferredMixerAttributes}};
static const JNINativeMethod gEventHandlerMethods[] = {
{"native_setup",
@@ -3283,9 +3527,12 @@ int register_android_media_AudioSystem(JNIEnv *env)
jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
+ gAudioFormatCstor = GetMethodIDOrDie(env, audioFormatClass, "<init>", "(IIIII)V");
gAudioFormatFields.mEncoding = GetFieldIDOrDie(env, audioFormatClass, "mEncoding", "I");
gAudioFormatFields.mSampleRate = GetFieldIDOrDie(env, audioFormatClass, "mSampleRate", "I");
gAudioFormatFields.mChannelMask = GetFieldIDOrDie(env, audioFormatClass, "mChannelMask", "I");
+ gAudioFormatFields.mChannelIndexMask =
+ GetFieldIDOrDie(env, audioFormatClass, "mChannelIndexMask", "I");
jclass audioMixingRuleClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule");
gAudioMixingRuleClass = MakeGlobalRefOrDie(env, audioMixingRuleClass);
@@ -3359,6 +3606,15 @@ int register_android_media_AudioSystem(JNIEnv *env)
gVibratorMethods.getMaxAmplitude =
GetMethodIDOrDie(env, vibratorClass, "getHapticChannelMaximumAmplitude", "()F");
+ jclass audioMixerAttributesClass = FindClassOrDie(env, "android/media/AudioMixerAttributes");
+ gAudioMixerAttributesClass = MakeGlobalRefOrDie(env, audioMixerAttributesClass);
+ gAudioMixerAttributesCstor = GetMethodIDOrDie(env, audioMixerAttributesClass, "<init>",
+ "(Landroid/media/AudioFormat;I)V");
+ gAudioMixerAttributesField.mFormat = GetFieldIDOrDie(env, audioMixerAttributesClass, "mFormat",
+ "Landroid/media/AudioFormat;");
+ gAudioMixerAttributesField.mMixerBehavior =
+ GetFieldIDOrDie(env, audioMixerAttributesClass, "mMixerBehavior", "I");
+
AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback);
RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 5e0d9b32380c..fe957624cf4b 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -587,6 +587,13 @@ enum {
MEMINFO_ACTIVE,
MEMINFO_INACTIVE,
MEMINFO_UNEVICTABLE,
+ MEMINFO_AVAILABLE,
+ MEMINFO_ACTIVE_ANON,
+ MEMINFO_INACTIVE_ANON,
+ MEMINFO_ACTIVE_FILE,
+ MEMINFO_INACTIVE_FILE,
+ MEMINFO_CMA_TOTAL,
+ MEMINFO_CMA_FREE,
MEMINFO_COUNT
};
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 593482c9deac..34589b7c9585 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1906,6 +1906,11 @@ static jobject nativeGetDefaultApplyToken(JNIEnv* env, jclass clazz) {
return javaObjectForIBinder(env, token);
}
+static jboolean nativeBootFinished(JNIEnv* env, jclass clazz) {
+ status_t error = SurfaceComposerClient::bootFinished();
+ return error == OK ? JNI_TRUE : JNI_FALSE;
+}
+
// ----------------------------------------------------------------------------
SurfaceControl* android_view_SurfaceControl_getNativeSurfaceControl(JNIEnv* env,
@@ -2138,6 +2143,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDefaultApplyToken },
{"nativeGetDefaultApplyToken", "()Landroid/os/IBinder;",
(void*)nativeGetDefaultApplyToken },
+ {"nativeBootFinished", "()Z",
+ (void*)nativeBootFinished },
// clang-format on
};
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 907093343a3f..a4463e4e96c5 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -16,7 +16,6 @@ roosa@google.com
per-file package_item_info.proto = toddke@google.com,patb@google.com
per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/android/app/usage/OWNERS
per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
-per-file android/hardware/sensorprivacy.proto = ntmyren@google.com,evanseverson@google.com,ewol@google.com
# Biometrics
jaggies@google.com
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 09672c2db47f..2cf241f9b249 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3349,6 +3349,14 @@
android:description="@string/permdesc_companionProfileWatch"
android:protectionLevel="normal" />
+ <!-- Allows app to request to be associated with a device via
+ {@link android.companion.CompanionDeviceManager}
+ as "glasses"
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_GLASSES"
+ android:protectionLevel="normal" />
+
<!-- Allows application to request to be associated with a virtual display capable of streaming
Android applications
({@link android.companion.AssociationRequest#DEVICE_PROFILE_APP_STREAMING})
@@ -3358,6 +3366,14 @@
<permission android:name="android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING"
android:protectionLevel="signature|privileged" />
+ <!-- Allows application to request to stream content from an Android host to a nearby device
+ ({@link android.companion.AssociationRequest#DEVICE_PROFILE_NEARBY_DEVICE_STREAMING})
+ by {@link android.companion.CompanionDeviceManager}.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows application to request to be associated with a vehicle head unit capable of
automotive projection
({@link android.companion.AssociationRequest#DEVICE_PROFILE_AUTOMOTIVE_PROJECTION})
@@ -3847,6 +3863,11 @@
<permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION"
android:protectionLevel="signature" />
+ <!-- Allows an application to get enabled credential manager providers.
+ @hide -->
+ <permission android:name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS"
+ android:protectionLevel="signature|privileged" />
+
<!-- ========================================= -->
<!-- Permissions for special development tools -->
<!-- ========================================= -->
@@ -4916,7 +4937,7 @@
<!-- Allows an application to manage the companion devices.
@hide -->
<permission android:name="android.permission.MANAGE_COMPANION_DEVICES"
- android:protectionLevel="signature|role" />
+ android:protectionLevel="module|signature|role" />
<!-- Allows an application to subscribe to notifications about the presence status change
of their associated companion device
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cead34b6231c..2fb766e46c5e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3422,6 +3422,11 @@
phone object irrespective of this config -->
<bool name="config_switch_phone_on_voice_reg_state_change">true</bool>
+ <!-- Config determines whether Memory Availability Notification is supported over Ims so that
+ the RP-SMMA Notification is sent over Ims to SMS Service center indicating that UE can now
+ start receiving SMS after failures due to Memory Full event -->
+ <bool name="config_smma_notification_supported_over_ims">false</bool>
+
<bool name="config_sms_force_7bit_encoding">false</bool>
<!-- Number of physical SIM slots on the device. This includes both eSIM and pSIM slots, and
@@ -4765,11 +4770,11 @@
<integer name="config_defaultPeakRefreshRate">0</integer>
<!-- The display uses different gamma curves for different refresh rates. It's hard for panel
- vendor to tune the curves to have exact same brightness for different refresh rate. So
+ vendors to tune the curves to have exact same brightness for different refresh rate. So
flicker could be observed at switch time. The issue is worse at the gamma lower end.
In addition, human eyes are more sensitive to the flicker at darker environment.
To prevent flicker, we only support higher refresh rates if the display brightness is above
- a threshold. And the darker environment could have higher threshold.
+ a threshold.
For example, no higher refresh rate if
display brightness <= disp0 && ambient brightness <= amb0
|| display brightness <= disp1 && ambient brightness <= amb1 -->
@@ -4791,13 +4796,12 @@
<integer name="config_defaultRefreshRateInZone">0</integer>
<!-- The display uses different gamma curves for different refresh rates. It's hard for panel
- vendor to tune the curves to have exact same brightness for different refresh rate. So
+ vendors to tune the curves to have exact same brightness for different refresh rate. So
flicker could be observed at switch time. The issue can be observed on the screen with
even full white content at the high brightness. To prevent flickering, we support fixed
refresh rates if the display and ambient brightness are equal to or above the provided
thresholds. You can define multiple threshold levels as higher brightness environments
- may have lower display brightness requirements for the flickering is visible. And the
- high brightness environment could have higher threshold.
+ may have lower display brightness requirements for the flickering is visible.
For example, fixed refresh rate if
display brightness >= disp0 && ambient brightness >= amb0
|| display brightness >= disp1 && ambient brightness >= amb1 -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 18a5c72b0892..8106e247ae63 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -139,9 +139,9 @@
<!-- Displayed when a SIM PUK password is too short. -->
<string name="invalidPuk">Type a PUK that is 8 numbers or longer.</string>
<!-- Displayed to prompt the user to type the PUK password to unlock
- the SIM card. -->
- <string name="needPuk">Your SIM card is PUK-locked. Type the PUK code to unlock it.</string>
- <string name="needPuk2">Type PUK2 to unblock SIM card.</string>
+ the SIM. -->
+ <string name="needPuk">Your SIM is PUK-locked. Type the PUK code to unlock it.</string>
+ <string name="needPuk2">Type PUK2 to unblock SIM.</string>
<!-- Displayed when user attempts to change SIM PIN1 without enabling PIN1. -->
<string name="enablePin">Unsuccessful, enable SIM/RUIM Lock.</string>
<!-- Displayed when a SIM PIN/PUK is entered incorrectly. -->
@@ -2529,23 +2529,23 @@
<!-- Shown when face unlock failed multiple times so we're just using the backup -->
<string name="faceunlock_multiple_failures">Maximum Face Unlock attempts exceeded</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message_short">No SIM card</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message" product="tablet">No SIM card in tablet.</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message" product="tv">No SIM card in your Android TV device.</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message" product="default">No SIM card in phone.</string>
- <!-- Shown in the lock screen to ask the user to insert a SIM card. -->
- <string name="lockscreen_missing_sim_instructions">Insert a SIM card.</string>
- <!-- Shown in the lock screen to ask the user to insert a SIM card when sim is missing or not readable. -->
- <string name="lockscreen_missing_sim_instructions_long">The SIM card is missing or not readable. Insert a SIM card.</string>
- <!-- Shown in the lock screen when SIM card is permanently disabled. -->
- <string name="lockscreen_permanent_disabled_sim_message_short">Unusable SIM card.</string>
- <!-- Shown in the lock screen to inform the user to SIM card is permanently disabled. -->
- <string name="lockscreen_permanent_disabled_sim_instructions">Your SIM card has been permanently disabled.\n
- Contact your wireless service provider for another SIM card.</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message_short">No SIM</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message" product="tablet">No SIM in tablet.</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message" product="tv">No SIM in your Android TV device.</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message" product="default">No SIM in phone.</string>
+ <!-- Shown in the lock screen to ask the user to add a SIM. -->
+ <string name="lockscreen_missing_sim_instructions">Add a SIM.</string>
+ <!-- Shown in the lock screen to ask the user to add a SIM when sim is missing or not readable. -->
+ <string name="lockscreen_missing_sim_instructions_long">The SIM is missing or not readable. Add a SIM.</string>
+ <!-- Shown in the lock screen when SIM is permanently disabled. -->
+ <string name="lockscreen_permanent_disabled_sim_message_short">Unusable SIM.</string>
+ <!-- Shown in the lock screen to inform the user to SIM is permanently deactivated. -->
+ <string name="lockscreen_permanent_disabled_sim_instructions">Your SIM has been permanently deactivated.\n
+ Contact your wireless service provider for another SIM.</string>
<!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
<string name="lockscreen_transport_prev_description">Previous track</string>
@@ -2572,17 +2572,17 @@
<!-- When the user enters a wrong sim pin too many times, it becomes
PUK locked (Pin Unlock Kode) -->
- <string name="lockscreen_sim_puk_locked_message">SIM card is PUK-locked.</string>
+ <string name="lockscreen_sim_puk_locked_message">SIM is PUK-locked.</string>
<!-- Shown in the lock screen when the SIM has become PUK locked and the user must call customer care to unlock it. -->
<string name="lockscreen_sim_puk_locked_instructions">See the User Guide or contact Customer Care.</string>
<!-- Shown in the lock screen to tell the user that their SIM is locked and they must unlock it. -->
- <string name="lockscreen_sim_locked_message">SIM card is locked.</string>
+ <string name="lockscreen_sim_locked_message">SIM is locked.</string>
<!-- For the unlock screen, When the user enters a sim unlock code, it takes a little while to check
whether it is valid, and to unlock the sim if it is valid. we display a
progress dialog in the meantime. this is the emssage. -->
- <string name="lockscreen_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- For the unlock screen, Information message shown in dialog when user has too many failed attempts at
drawing the unlock pattern -->
@@ -3883,13 +3883,13 @@
<!-- SIM swap and device reboot Dialog --> <skip />
<!-- See SIM_REMOVED_DIALOG. This is the title of that dialog. -->
- <string name="sim_removed_title">SIM card removed</string>
+ <string name="sim_removed_title">SIM removed</string>
<!-- See SIM_REMOVED_DIALOG. This is the message of that dialog. -->
- <string name="sim_removed_message">The mobile network will be unavailable until you restart with a valid SIM card inserted.</string>
+ <string name="sim_removed_message">The mobile network will be unavailable until you restart with a valid SIM.</string>
<!-- See SIM_REMOVED_DIALOG. This is the button of that dialog. -->
<string name="sim_done_button">Done</string>
<!-- See SIM_ADDED_DIALOG. This is the title of that dialog. -->
- <string name="sim_added_title">SIM card added</string>
+ <string name="sim_added_title">SIM added</string>
<!-- See SIM_ADDED_DIALOG. This is the message of that dialog. -->
<string name="sim_added_message">Restart your device to access the mobile network.</string>
<!-- See SIM_ADDED_DIALOG. This is the button of that dialog. -->
@@ -4713,8 +4713,8 @@
<string name="kg_puk_enter_pin_hint">Enter desired PIN code</string>
<!-- Message shown when the user needs to confirm the PIN they just entered in the PUK screen -->
<string name="kg_enter_confirm_pin_hint">Confirm desired PIN code</string>
- <!-- Message shown in dialog while the device is unlocking the SIM card -->
- <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <!-- Message shown in dialog while the device is unlocking the SIM -->
+ <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- Message shown when the user enters the wrong PIN code -->
<string name="kg_password_wrong_pin_code">Incorrect PIN code.</string>
<!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
@@ -4937,7 +4937,7 @@
<!-- Title of Color Correction feature, which is mostly used to help users who are colorblind,
shown in the warning dialog about the accessibility shortcut. -->
- <string name="color_correction_feature_name">Color Correction</string>
+ <string name="color_correction_feature_name">Color correction</string>
<!-- Title of One Handed Mode feature, shown in the system gestures of the accessibility shortcut. [CHAR LIMIT=none] -->
<string name="one_handed_mode_feature_name">One-Handed mode</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd0024feae7e..e8304d801ab2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2810,6 +2810,7 @@
<java-symbol type="bool" name="config_switch_phone_on_voice_reg_state_change" />
<java-symbol type="string" name="whichHomeApplicationNamed" />
<java-symbol type="string" name="whichHomeApplicationLabel" />
+ <java-symbol type="bool" name="config_smma_notification_supported_over_ims" />
<java-symbol type="bool" name="config_sms_force_7bit_encoding" />
<java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" />
<java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" />
diff --git a/core/tests/coretests/src/android/companion/virtual/OWNERS b/core/tests/coretests/src/android/companion/virtual/OWNERS
new file mode 100644
index 000000000000..1a3e927a106f
--- /dev/null
+++ b/core/tests/coretests/src/android/companion/virtual/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include /services/companion/java/com/android/server/companion/virtual/OWNERS \ No newline at end of file
diff --git a/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java b/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java
new file mode 100644
index 000000000000..694b3128998c
--- /dev/null
+++ b/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.camera;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.graphics.PixelFormat;
+import android.hardware.camera2.params.InputConfiguration;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class VirtualCameraOutputTest {
+
+ private static final String TAG = "VirtualCameraOutputTest";
+
+ private ExecutorService mExecutor;
+
+ private InputConfiguration mConfiguration;
+
+ @Before
+ public void setUp() {
+ mExecutor = Executors.newSingleThreadExecutor();
+ mConfiguration = new InputConfiguration(64, 64, PixelFormat.RGB_888);
+ }
+
+ @After
+ public void cleanUp() {
+ mExecutor.shutdownNow();
+ }
+
+ @Test
+ public void createStreamDescriptor_successfulDataStream() {
+ byte[] cameraData = new byte[]{1, 2, 3, 4, 5};
+ VirtualCameraInput input = createCameraInput(cameraData);
+ VirtualCameraOutput output = new VirtualCameraOutput(input, mExecutor);
+ ParcelFileDescriptor descriptor = output.getStreamDescriptor(mConfiguration);
+
+ try (FileInputStream fis = new FileInputStream(descriptor.getFileDescriptor())) {
+ byte[] receivedData = fis.readNBytes(cameraData.length);
+
+ output.closeStream();
+ assertThat(receivedData).isEqualTo(cameraData);
+ } catch (IOException exception) {
+ fail("Unable to read bytes from FileInputStream. Message: " + exception.getMessage());
+ }
+ }
+
+ @Test
+ public void createStreamDescriptor_multipleCallsSameStream() {
+ VirtualCameraInput input = createCameraInput(new byte[]{0});
+ VirtualCameraOutput output = new VirtualCameraOutput(input, mExecutor);
+
+ ParcelFileDescriptor firstDescriptor = output.getStreamDescriptor(mConfiguration);
+ ParcelFileDescriptor secondDescriptor = output.getStreamDescriptor(mConfiguration);
+
+ assertThat(firstDescriptor).isSameInstanceAs(secondDescriptor);
+ }
+
+ @Test
+ public void createStreamDescriptor_differentStreams() {
+ VirtualCameraInput input = createCameraInput(new byte[]{0});
+ VirtualCameraOutput callback = new VirtualCameraOutput(input, mExecutor);
+
+ InputConfiguration differentConfig = new InputConfiguration(mConfiguration.getWidth() + 1,
+ mConfiguration.getHeight() + 1, mConfiguration.getFormat());
+
+ ParcelFileDescriptor firstDescriptor = callback.getStreamDescriptor(mConfiguration);
+ ParcelFileDescriptor secondDescriptor = callback.getStreamDescriptor(differentConfig);
+
+ assertThat(firstDescriptor).isNotSameInstanceAs(secondDescriptor);
+ }
+
+ private VirtualCameraInput createCameraInput(byte[] data) {
+ return new VirtualCameraInput() {
+ private ByteArrayInputStream mInputStream = null;
+
+ @Override
+ @NonNull
+ public InputStream openStream(@NonNull InputConfiguration inputConfiguration) {
+ closeStream();
+ mInputStream = new ByteArrayInputStream(data);
+ return mInputStream;
+ }
+
+ @Override
+ public void closeStream() {
+ if (mInputStream == null) {
+ return;
+ }
+ try {
+ mInputStream.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to close image stream.", e);
+ }
+ mInputStream = null;
+ }
+ };
+ }
+}
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index bc356f80dca1..324f81084f98 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -16,7 +16,7 @@
package android.content;
-import static android.companion.virtual.VirtualDeviceManager.DEFAULT_DEVICE_ID;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -216,7 +216,7 @@ public class ContextTest {
final Context systemContext =
ActivityThread.currentActivityThread().getSystemContext();
- assertEquals(systemContext.getDeviceId(), DEFAULT_DEVICE_ID);
+ assertEquals(systemContext.getDeviceId(), DEVICE_ID_DEFAULT);
}
@Test
@@ -224,7 +224,7 @@ public class ContextTest {
final Context systemUiContext =
ActivityThread.currentActivityThread().getSystemUiContext();
- assertEquals(systemUiContext.getDeviceId(), DEFAULT_DEVICE_ID);
+ assertEquals(systemUiContext.getDeviceId(), DEVICE_ID_DEFAULT);
}
@Test
@@ -232,7 +232,7 @@ public class ContextTest {
final Context testContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
- assertEquals(testContext.getDeviceId(), DEFAULT_DEVICE_ID);
+ assertEquals(testContext.getDeviceId(), DEVICE_ID_DEFAULT);
}
private Context createUiContext() {
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index 8e63a0fe3364..ef38cdec0d63 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -22,12 +22,12 @@ import static android.os.Environment.HAS_DOWNLOADS;
import static android.os.Environment.HAS_OTHER;
import static android.os.Environment.classifyExternalStorageDirectory;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import android.app.AppOpsManager;
import android.content.Context;
+import android.os.storage.StorageManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +38,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
+import java.util.ArrayList;
+import java.util.UUID;
+import java.util.function.BiFunction;
@RunWith(AndroidJUnit4.class)
public class EnvironmentTest {
@@ -104,4 +107,42 @@ public class EnvironmentTest {
Environment.buildPath(dir, "Taxes.pdf").createNewFile();
assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
}
+
+ @Test
+ public void testDataCePackageDirectoryForUser() {
+ testDataPackageDirectoryForUser(
+ (uuid, userHandle) -> Environment.getDataCePackageDirectoryForUser(
+ uuid, userHandle, getContext().getPackageName()),
+ (uuid, user) -> Environment.getDataUserCePackageDirectory(
+ uuid, user, getContext().getPackageName())
+ );
+ }
+
+ @Test
+ public void testDataDePackageDirectoryForUser() {
+ testDataPackageDirectoryForUser(
+ (uuid, userHandle) -> Environment.getDataDePackageDirectoryForUser(
+ uuid, userHandle, getContext().getPackageName()),
+ (uuid, user) -> Environment.getDataUserDePackageDirectory(
+ uuid, user, getContext().getPackageName())
+ );
+ }
+
+ private void testDataPackageDirectoryForUser(
+ BiFunction<UUID, UserHandle, File> publicApi,
+ BiFunction<String, Integer, File> hideApi) {
+ var uuids = new ArrayList<String>();
+ uuids.add(null); // Private internal
+ uuids.add("primary_physical");
+ uuids.add("system");
+ uuids.add("3939-3939"); // FAT Volume
+ uuids.add("57554103-df3e-4475-ae7a-8feba49353ac"); // Random valid UUID
+ var userHandle = UserHandle.of(0);
+
+ // Check that the @hide method is consistent with the public API
+ for (String uuid : uuids) {
+ assertThat(publicApi.apply(StorageManager.convert(uuid), userHandle))
+ .isEqualTo(hideApi.apply(uuid, 0));
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 7674135719e9..8f83461baea7 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -20,7 +20,6 @@ import static android.text.TextUtils.formatSimple;
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_LAUNCH_CAMERA;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_ADD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_APP_START;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_HEADS_UP_APPEAR;
@@ -32,7 +31,6 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_ROW_EXPAND;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_ROW_SWIPE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLIT_SCREEN_RESIZE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_TO_STATSD_INTERACTION_TYPE;
import static com.android.internal.jank.InteractionJankMonitor.MAX_LENGTH_OF_CUJ_NAME;
import static com.android.internal.jank.InteractionJankMonitor.getNameOfCuj;
@@ -92,7 +90,6 @@ import java.util.stream.Collectors;
public class InteractionJankMonitorTest {
private static final String CUJ_POSTFIX = "";
private static final SparseArray<String> ENUM_NAME_EXCEPTION_MAP = new SparseArray<>();
- private static final SparseArray<String> CUJ_NAME_EXCEPTION_MAP = new SparseArray<>();
private static final String ENUM_NAME_PREFIX =
"UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__";
@@ -129,22 +126,6 @@ public class InteractionJankMonitorTest {
CUJ_NOTIFICATION_SHADE_ROW_SWIPE, getEnumName("SHADE_ROW_SWIPE"));
ENUM_NAME_EXCEPTION_MAP.put(
CUJ_NOTIFICATION_SHADE_SCROLL_FLING, getEnumName("SHADE_SCROLL_FLING"));
-
- CUJ_NAME_EXCEPTION_MAP.put(
- CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, "CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE");
- CUJ_NAME_EXCEPTION_MAP.put(
- CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
- "CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE");
- CUJ_NAME_EXCEPTION_MAP.put(
- CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE, "CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE");
- CUJ_NAME_EXCEPTION_MAP.put(
- CUJ_NOTIFICATION_SHADE_ROW_EXPAND, "CUJ_NOTIFICATION_SHADE_ROW_EXPAND");
- CUJ_NAME_EXCEPTION_MAP.put(
- CUJ_NOTIFICATION_SHADE_ROW_SWIPE, "CUJ_NOTIFICATION_SHADE_ROW_SWIPE");
- CUJ_NAME_EXCEPTION_MAP.put(
- CUJ_NOTIFICATION_SHADE_SCROLL_FLING, "CUJ_NOTIFICATION_SHADE_SCROLL_FLING");
- CUJ_NAME_EXCEPTION_MAP.put(CUJ_LOCKSCREEN_LAUNCH_CAMERA, "CUJ_LOCKSCREEN_LAUNCH_CAMERA");
- CUJ_NAME_EXCEPTION_MAP.put(CUJ_SPLIT_SCREEN_RESIZE, "CUJ_SPLIT_SCREEN_RESIZE");
}
private static String getEnumName(String name) {
@@ -272,9 +253,8 @@ public class InteractionJankMonitorTest {
: formatSimple("%s%s", ENUM_NAME_PREFIX, cujName.substring(4));
final int enumKey = CUJ_TO_STATSD_INTERACTION_TYPE[cuj];
final String enumName = enumsMap.get(enumKey);
- final String expectedNameOfCuj = CUJ_NAME_EXCEPTION_MAP.contains(cuj)
- ? CUJ_NAME_EXCEPTION_MAP.get(cuj)
- : formatSimple("CUJ_%s", getNameOfCuj(cuj));
+ final String expectedNameOfCuj = formatSimple("CUJ_%s", getNameOfCuj(cuj));
+
mExpect
.withMessage(formatSimple(
"%s (%d) not matches %s (%d)", cujName, cuj, enumName, enumKey))
@@ -323,7 +303,7 @@ public class InteractionJankMonitorTest {
// Since the length of the cuj name is tested in another test, no need to test it here.
// Too long postfix case, should trim the postfix and keep the cuj name completed.
final String expectedTrimmedName = formatSimple("J<%s::%s>", cujName,
- "ThisIsTheCujTagThisIsTheCujTagThisIsTheCujTagThisIsTheCujTagThisIsTheCujTagT...");
+ "ThisIsTheCujTagThisIsTheCujTagThisIsTheCujTagThisIsTheCujTagThi...");
Session longPostfix = new Session(cujType, tooLongTag);
assertThat(longPostfix.getName()).isEqualTo(expectedTrimmedName);
}
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index 3958bb71bfc9..e278c529d7a3 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -63,5 +63,6 @@
<permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
<permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
+ <permission name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 3e2b71f18b75..4109425815c8 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -232,6 +232,7 @@ applications that come with the platform
<privapp-permissions package="com.android.shell">
<!-- Needed for test only -->
+ <permission name="android.permission.MANAGE_HEALTH_DATA"/>
<permission name="android.permission.LAUNCH_DEVICE_MANAGER_SETUP"/>
<permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.ACCESS_LOWPAN_STATE"/>
@@ -386,6 +387,7 @@ applications that come with the platform
<permission name="android.permission.MANAGE_COMPANION_DEVICES" />
<permission name="android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING" />
<permission name="android.permission.REQUEST_COMPANION_PROFILE_WATCH" />
+ <permission name="android.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING" />
<permission name="android.permission.REQUEST_COMPANION_PROFILE_COMPUTER" />
<permission name="android.permission.REQUEST_COMPANION_SELF_MANAGED" />
<!-- Permission required for testing registering pull atom callbacks. -->
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 33467404e38f..73f25b1b4899 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -805,6 +805,12 @@
"group": "WM_DEBUG_CONTENT_RECORDING",
"at": "com\/android\/server\/wm\/ContentRecorder.java"
},
+ "-1323783276": {
+ "message": "performEnableScreen: bootFinished() failed.",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-1318478129": {
"message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
"level": "VERBOSE",
@@ -1603,6 +1609,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-576580969": {
+ "message": "viewServerWindowCommand: bootFinished() failed.",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-576070986": {
"message": "Performing post-rotate rotation after seamless rotation",
"level": "INFO",
@@ -2113,12 +2125,6 @@
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
- "-87703044": {
- "message": "Boot completed: SurfaceFlinger is dead!",
- "level": "ERROR",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-86763148": {
"message": " KILL SURFACE SESSION %s",
"level": "INFO",
@@ -2911,12 +2917,6 @@
"group": "WM_DEBUG_CONTENT_RECORDING",
"at": "com\/android\/server\/wm\/ContentRecorder.java"
},
- "620368427": {
- "message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!",
- "level": "INFO",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"620519522": {
"message": "findFocusedWindow: No focusable windows, display=%d",
"level": "VERBOSE",
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index a43e2251d486..0f8616da7359 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -139,7 +139,7 @@ key 116 POWER
key 117 NUMPAD_EQUALS
# key 118 "KEY_KPPLUSMINUS"
key 119 BREAK
-# key 120 (undefined)
+key 120 RECENT_APPS
key 121 NUMPAD_COMMA
key 122 KANA
key 123 EISU
diff --git a/identity/java/android/security/identity/AuthenticationKeyMetadata.java b/identity/java/android/security/identity/AuthenticationKeyMetadata.java
new file mode 100644
index 000000000000..d4c28f8d459a
--- /dev/null
+++ b/identity/java/android/security/identity/AuthenticationKeyMetadata.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+
+import java.time.Instant;
+
+/**
+ * Data about authentication keys.
+ */
+public class AuthenticationKeyMetadata {
+ private int mUsageCount;
+ private Instant mExpirationDate;
+
+ AuthenticationKeyMetadata(int usageCount, Instant expirationDate) {
+ mUsageCount = usageCount;
+ mExpirationDate = expirationDate;
+ }
+
+ /**
+ * Gets usage count for the authentication key.
+ *
+ * @return the usage count
+ */
+ public @IntRange(from = 0) int getUsageCount() {
+ return mUsageCount;
+ }
+
+ /**
+ * Gets expiration date for the authentication key.
+ *
+ * @return the expiration date of the authentication key.
+ */
+ public @NonNull Instant getExpirationDate() {
+ return mExpirationDate;
+ }
+}
diff --git a/identity/java/android/security/identity/CredentialDataResult.java b/identity/java/android/security/identity/CredentialDataResult.java
index beb03af46303..dca039a06a0d 100644
--- a/identity/java/android/security/identity/CredentialDataResult.java
+++ b/identity/java/android/security/identity/CredentialDataResult.java
@@ -106,6 +106,30 @@ public abstract class CredentialDataResult {
public abstract @Nullable byte[] getDeviceMac();
/**
+ * Returns a signature over the {@code DeviceAuthenticationBytes} CBOR
+ * specified in {@link #getDeviceNameSpaces()}, to prove to the reader that the data
+ * is from a trusted credential.
+ *
+ * <p>The signature is made using the authentication private key. See section 9.1.3.4 of
+ * ISO/IEC 18013-5:2021 for details of this operation.
+ *
+ * <p>If the session transcript or reader ephemeral key wasn't set on the {@link
+ * PresentationSession} used to obtain this data no signature will be produced and this method
+ * will return {@code null}.
+ *
+ * <p>This is only implemented in feature version 202301 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @return A COSE_Sign1 structure as described above or {@code null} if the conditions
+ * specified above are not met.
+ */
+ public @Nullable byte[] getDeviceSignature() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Returns the static authentication data associated with the dynamic authentication
* key used to MAC the data returned by {@link #getDeviceNameSpaces()}.
*
diff --git a/identity/java/android/security/identity/CredstoreCredentialDataResult.java b/identity/java/android/security/identity/CredstoreCredentialDataResult.java
index 7afe3d448bf9..b4fd5d3fe5a7 100644
--- a/identity/java/android/security/identity/CredstoreCredentialDataResult.java
+++ b/identity/java/android/security/identity/CredstoreCredentialDataResult.java
@@ -47,6 +47,11 @@ class CredstoreCredentialDataResult extends CredentialDataResult {
}
@Override
+ public @Nullable byte[] getDeviceSignature() {
+ return mDeviceSignedResult.getSignature();
+ }
+
+ @Override
public @NonNull byte[] getStaticAuthenticationData() {
return mDeviceSignedResult.getStaticAuthenticationData();
}
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java
index c591c879059c..449c7a706753 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java
@@ -60,16 +60,19 @@ class CredstoreIdentityCredential extends IdentityCredential {
private Context mContext;
private ICredential mBinder;
private CredstorePresentationSession mSession;
+ private int mFeatureVersion;
CredstoreIdentityCredential(Context context, String credentialName,
@IdentityCredentialStore.Ciphersuite int cipherSuite,
ICredential binder,
- @Nullable CredstorePresentationSession session) {
+ @Nullable CredstorePresentationSession session,
+ int featureVersion) {
mContext = context;
mCredentialName = credentialName;
mCipherSuite = cipherSuite;
mBinder = binder;
mSession = session;
+ mFeatureVersion = featureVersion;
}
private KeyPair mEphemeralKeyPair = null;
@@ -347,12 +350,18 @@ class CredstoreIdentityCredential extends IdentityCredential {
}
}
+ byte[] signature = resultParcel.signature;
+ if (signature != null && signature.length == 0) {
+ signature = null;
+ }
+
byte[] mac = resultParcel.mac;
if (mac != null && mac.length == 0) {
mac = null;
}
CredstoreResultData.Builder resultDataBuilder = new CredstoreResultData.Builder(
- resultParcel.staticAuthenticationData, resultParcel.deviceNameSpaces, mac);
+ mFeatureVersion, resultParcel.staticAuthenticationData,
+ resultParcel.deviceNameSpaces, mac, signature);
for (ResultNamespaceParcel resultNamespaceParcel : resultParcel.resultNamespaces) {
for (ResultEntryParcel resultEntryParcel : resultNamespaceParcel.entries) {
@@ -371,8 +380,14 @@ class CredstoreIdentityCredential extends IdentityCredential {
@Override
public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+ setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, 0);
+ }
+
+ @Override
+ public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+ long minValidTimeMillis) {
try {
- mBinder.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+ mBinder.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, minValidTimeMillis);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
} catch (android.os.ServiceSpecificException e) {
@@ -472,6 +487,34 @@ class CredstoreIdentityCredential extends IdentityCredential {
}
@Override
+ public @NonNull List<AuthenticationKeyMetadata> getAuthenticationKeyMetadata() {
+ try {
+ int[] usageCount = mBinder.getAuthenticationDataUsageCount();
+ long[] expirationsMillis = mBinder.getAuthenticationDataExpirations();
+ if (usageCount.length != expirationsMillis.length) {
+ throw new IllegalStateException("Size og usageCount and expirationMillis differ");
+ }
+ List<AuthenticationKeyMetadata> mds = new ArrayList<>();
+ for (int n = 0; n < expirationsMillis.length; n++) {
+ AuthenticationKeyMetadata md = null;
+ long expirationMillis = expirationsMillis[n];
+ if (expirationMillis != Long.MAX_VALUE) {
+ md = new AuthenticationKeyMetadata(
+ usageCount[n],
+ Instant.ofEpochMilli(expirationMillis));
+ }
+ mds.add(md);
+ }
+ return mds;
+ } catch (android.os.RemoteException e) {
+ throw new IllegalStateException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new IllegalStateException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override
public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
try {
byte[] proofOfOwnership = mBinder.proveOwnership(challenge);
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
index bbaf0862f923..d785c3c895b8 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
@@ -19,6 +19,8 @@ package android.security.identity;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.security.GenerateRkpKey;
@@ -30,10 +32,28 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore {
private Context mContext = null;
private ICredentialStore mStore = null;
+ private int mFeatureVersion;
+
+ static int getFeatureVersion(@NonNull Context context) {
+ PackageManager pm = context.getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE)) {
+ FeatureInfo[] infos = pm.getSystemAvailableFeatures();
+ for (int n = 0; n < infos.length; n++) {
+ FeatureInfo info = infos[n];
+ if (info.name.equals(PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE)) {
+ return info.version;
+ }
+ }
+ }
+ // Use of the system feature is not required since Android 12. So for Android 11
+ // return 202009 which is the feature version shipped with Android 11.
+ return 202009;
+ }
private CredstoreIdentityCredentialStore(@NonNull Context context, ICredentialStore store) {
mContext = context;
mStore = store;
+ mFeatureVersion = getFeatureVersion(mContext);
}
static CredstoreIdentityCredentialStore getInstanceForType(@NonNull Context context,
@@ -139,8 +159,7 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore {
ICredential credstoreCredential;
credstoreCredential = mStore.getCredentialByName(credentialName, cipherSuite);
return new CredstoreIdentityCredential(mContext, credentialName, cipherSuite,
- credstoreCredential,
- null);
+ credstoreCredential, null, mFeatureVersion);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
} catch (android.os.ServiceSpecificException e) {
@@ -182,7 +201,8 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore {
throws CipherSuiteNotSupportedException {
try {
ISession credstoreSession = mStore.createPresentationSession(cipherSuite);
- return new CredstorePresentationSession(mContext, cipherSuite, this, credstoreSession);
+ return new CredstorePresentationSession(mContext, cipherSuite, this, credstoreSession,
+ mFeatureVersion);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
} catch (android.os.ServiceSpecificException e) {
diff --git a/identity/java/android/security/identity/CredstorePresentationSession.java b/identity/java/android/security/identity/CredstorePresentationSession.java
index e3c6689a8914..96bda5215c6d 100644
--- a/identity/java/android/security/identity/CredstorePresentationSession.java
+++ b/identity/java/android/security/identity/CredstorePresentationSession.java
@@ -48,15 +48,18 @@ class CredstorePresentationSession extends PresentationSession {
private byte[] mSessionTranscript = null;
private boolean mOperationHandleSet = false;
private long mOperationHandle = 0;
+ private int mFeatureVersion = 0;
CredstorePresentationSession(Context context,
@IdentityCredentialStore.Ciphersuite int cipherSuite,
CredstoreIdentityCredentialStore store,
- ISession binder) {
+ ISession binder,
+ int featureVersion) {
mContext = context;
mCipherSuite = cipherSuite;
mStore = store;
mBinder = binder;
+ mFeatureVersion = featureVersion;
}
private void ensureEphemeralKeyPair() {
@@ -147,7 +150,7 @@ class CredstorePresentationSession extends PresentationSession {
mBinder.getCredentialForPresentation(credentialName);
credential = new CredstoreIdentityCredential(mContext, credentialName,
mCipherSuite, credstoreCredential,
- this);
+ this, mFeatureVersion);
mCredentialCache.put(credentialName, credential);
credential.setAllowUsingExhaustedKeys(request.isAllowUsingExhaustedKeys());
diff --git a/identity/java/android/security/identity/CredstoreResultData.java b/identity/java/android/security/identity/CredstoreResultData.java
index 2ef735eec81d..57c04369203c 100644
--- a/identity/java/android/security/identity/CredstoreResultData.java
+++ b/identity/java/android/security/identity/CredstoreResultData.java
@@ -30,10 +30,11 @@ import java.util.Map;
* data requested from a {@link IdentityCredential}.
*/
class CredstoreResultData extends ResultData {
-
+ int mFeatureVersion = 0;
byte[] mStaticAuthenticationData = null;
byte[] mAuthenticatedData = null;
byte[] mMessageAuthenticationCode = null;
+ byte[] mSignature = null;
private Map<String, Map<String, EntryData>> mData = new LinkedHashMap<>();
@@ -61,6 +62,14 @@ class CredstoreResultData extends ResultData {
}
@Override
+ @Nullable byte[] getSignature() {
+ if (mFeatureVersion < 202301) {
+ throw new UnsupportedOperationException();
+ }
+ return mSignature;
+ }
+
+ @Override
public @NonNull byte[] getStaticAuthenticationData() {
return mStaticAuthenticationData;
}
@@ -124,13 +133,17 @@ class CredstoreResultData extends ResultData {
static class Builder {
private CredstoreResultData mResultData;
- Builder(byte[] staticAuthenticationData,
+ Builder(int featureVersion,
+ byte[] staticAuthenticationData,
byte[] authenticatedData,
- byte[] messageAuthenticationCode) {
+ byte[] messageAuthenticationCode,
+ byte[] signature) {
this.mResultData = new CredstoreResultData();
+ this.mResultData.mFeatureVersion = featureVersion;
this.mResultData.mStaticAuthenticationData = staticAuthenticationData;
this.mResultData.mAuthenticatedData = authenticatedData;
this.mResultData.mMessageAuthenticationCode = messageAuthenticationCode;
+ this.mResultData.mSignature = signature;
}
private Map<String, EntryData> getOrCreateInnerMap(String namespaceName) {
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index f440b693a5b3..2dd9778a6fe7 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -16,6 +16,7 @@
package android.security.identity;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -25,6 +26,7 @@ import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -236,14 +238,15 @@ public abstract class IdentityCredential {
* IntentToRetain = bool
* </pre>
*
- * <p>If the {@code sessionTranscript} parameter is not {@code null}, the X and Y coordinates
- * of the public part of the key-pair previously generated by {@link #createEphemeralKeyPair()}
- * must appear somewhere in the bytes of the CBOR. Each of these coordinates must appear
- * encoded with the most significant bits first and use the exact amount of bits indicated by
- * the key size of the ephemeral keys. For example, if the ephemeral key is using the P-256
- * curve then the 32 bytes for the X coordinate encoded with the most significant bits first
- * must appear somewhere in {@code sessionTranscript} and ditto for the 32 bytes for the Y
- * coordinate.
+ * <p>If mdoc session encryption is used (e.g. if {@link #createEphemeralKeyPair()} has been
+ * called) and if the {@code sessionTranscript} parameter is not {@code null}, the X and Y
+ * coordinates of the public part of the key-pair previously generated by
+ * {@link #createEphemeralKeyPair()} must appear somewhere in the bytes of the CBOR. Each of
+ * these coordinates must appear encoded with the most significant bits first and use the
+ * exact amount of bits indicated by the key size of the ephemeral keys. For example, if the
+ * ephemeral key is using the P-256 curve then the 32 bytes for the X coordinate encoded with
+ * the most significant bits first must appear somewhere in {@code sessionTranscript} and
+ * ditto for the 32 bytes for the Y coordinate.
*
* <p>If {@code readerSignature} is not {@code null} it must be the bytes of a
* {@code COSE_Sign1} structure as defined in RFC 8152. For the payload nil shall be used and
@@ -296,7 +299,7 @@ public abstract class IdentityCredential {
* session transcripts.
* @throws NoAuthenticationKeyAvailableException if authentication keys were never
* provisioned, the method
- * {@link #setAvailableAuthenticationKeys(int, int)}
+ * {@link #setAvailableAuthenticationKeys(int, int, long)}
* was called with {@code keyCount} set to 0,
* the method
* {@link #setAllowUsingExhaustedKeys(boolean)}
@@ -330,19 +333,25 @@ public abstract class IdentityCredential {
* for which this method has not been called behave as though it had been called wit
* {@code keyCount} 0 and {@code maxUsesPerKey} 1.
*
+ * <p>The effect of this method is like calling
+ * {@link #setAvailableAuthenticationKeys(int, int, long)} with the last parameter is set to 0.
+ *
* @param keyCount The number of active, certified dynamic authentication keys the
* {@code IdentityCredential} will try to keep available. This value
* must be non-negative.
* @param maxUsesPerKey The maximum number of times each of the keys will be used before it's
* eligible for replacement. This value must be greater than zero.
+ * @deprecated Use {@link #setAvailableAuthenticationKeys(int, int, long)} instead.
*/
+ @Deprecated
public abstract void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
/**
* Gets a collection of dynamic authentication keys that need certification.
*
* <p>When there aren't enough certified dynamic authentication keys, either because the key
- * count has been increased or because one or more keys have reached their usage count, this
+ * count has been increased or because one or more keys have reached their usage count or
+ * it if a key is too close to its expiration date, this
* method will generate replacement keys and certificates and return them for issuer
* certification. The issuer certificates and associated static authentication data must then
* be provided back to the Identity Credential using
@@ -400,11 +409,6 @@ public abstract class IdentityCredential {
* This should only be called for an authenticated key returned by
* {@link #getAuthKeysNeedingCertification()}.
*
- * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
- * fails with {@link UnsupportedOperationException}. See
- * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
- * feature versions.
- *
* @param authenticationKey The dynamic authentication key for which certification and
* associated static
* authentication data is being provided.
@@ -426,7 +430,9 @@ public abstract class IdentityCredential {
* Get the number of times the dynamic authentication keys have been used.
*
* @return int array of dynamic authentication key usage counts.
+ * @deprecated Use {@link #getAuthenticationKeyMetadata()} instead.
*/
+ @Deprecated
public @NonNull abstract int[] getAuthenticationDataUsageCount();
/**
@@ -519,4 +525,47 @@ public abstract class IdentityCredential {
public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Sets the number of dynamic authentication keys the {@code IdentityCredential} will maintain,
+ * the number of times each should be used, and the minimum amount of time it's valid for.
+ *
+ * <p>The Identity Credential system will select the least-used dynamic authentication key each
+ * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. Identity Credentials
+ * for which this method has not been called behave as though it had been called wit
+ * {@code keyCount} 0, {@code maxUsesPerKey} 1, and {@code minValidTimeMillis} 0.
+ *
+ * <p>Applications can use {@link #getAuthenticationKeyMetadata()} to get a picture of the
+ * usage andtime left of each configured authentication key. This can be used to determine
+ * how urgent it is recertify new authentication keys via the
+ * {@link #getAuthKeysNeedingCertification()} method.
+ *
+ * @param keyCount The number of active, certified dynamic authentication keys the
+ * {@code IdentityCredential} will try to keep available. This value
+ * must be non-negative.
+ * @param maxUsesPerKey The maximum number of times each of the keys will be used before it's
+ * eligible for replacement. This value must be greater than zero.
+ * @param minValidTimeMillis If a key has less time left than this value it will be eliglible
+ * for replacement. This value must be non-negative.
+ */
+ public void setAvailableAuthenticationKeys(
+ @IntRange(from = 0) int keyCount,
+ @IntRange(from = 1) int maxUsesPerKey,
+ @IntRange(from = 0) long minValidTimeMillis) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get information about dynamic authentication keys.
+ *
+ * <p>The returned list may have <code>null</code> values if certification for the dynamic
+ * authentication key is pending.
+ *
+ * <p>The list is always <code>keyCount</code> elements long.
+ *
+ * @return list of authentication key metadata objects.
+ */
+ public @NonNull List<AuthenticationKeyMetadata> getAuthenticationKeyMetadata() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/identity/java/android/security/identity/PresentationSession.java b/identity/java/android/security/identity/PresentationSession.java
index 6cde611fcd63..f392e121beca 100644
--- a/identity/java/android/security/identity/PresentationSession.java
+++ b/identity/java/android/security/identity/PresentationSession.java
@@ -73,7 +73,8 @@ public abstract class PresentationSession {
* <p>If called, this must be called before any calls to
* {@link #getCredentialData(String, CredentialDataRequest)}.
*
- * <p>The X and Y coordinates of the public part of the key-pair returned by {@link
+ * <p>If mdoc session encryption is used (e.g. if {@link #getEphemeralKeyPair()} has been
+ * called) then the X and Y coordinates of the public part of the key-pair returned by {@link
* #getEphemeralKeyPair()} must appear somewhere in the bytes of the passed in CBOR. Each of
* these coordinates must appear encoded with the most significant bits first and use the exact
* amount of bits indicated by the key size of the ephemeral keys. For example, if the
diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java
index d46f9854b278..8a0e56ed3184 100644
--- a/identity/java/android/security/identity/ResultData.java
+++ b/identity/java/android/security/identity/ResultData.java
@@ -134,6 +134,10 @@ public abstract class ResultData {
*/
public abstract @Nullable byte[] getMessageAuthenticationCode();
+ @Nullable byte[] getSignature() {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Returns the static authentication data associated with the dynamic authentication
* key used to sign or MAC the data returned by {@link #getAuthenticatedData()}.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index d3dc05fb92d4..5afb1d11ad45 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -20,11 +20,11 @@ import static android.app.ActivityManager.START_SUCCESS;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CLOSE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN;
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
@@ -340,7 +340,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
container.setInfo(wct, taskFragmentInfo);
if (container.isFinished()) {
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
} else {
// Update with the latest Task configuration.
@@ -376,22 +377,27 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Do not finish the dependents if the last activity is reparented to PiP.
// Instead, the original split should be cleanup, and the dependent may be
// expanded to fullscreen.
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
cleanupForEnterPip(wct, container);
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
} else if (taskFragmentInfo.isTaskClearedForReuse()) {
// Do not finish the dependents if this TaskFragment was cleared due to
// launching activity in the Task.
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
} else if (taskFragmentInfo.isClearedForReorderActivityToFront()) {
// Do not finish the dependents if this TaskFragment was cleared to reorder
// the launching Activity to front of the Task.
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
} else if (!container.isWaitingActivityAppear()) {
// Do not finish the container before the expected activity appear until
// timeout.
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
mPresenter.cleanupContainer(wct, container, true /* shouldFinishDependent */);
}
} else if (wasInPip && isInPip) {
@@ -585,7 +591,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
container.setInfo(wct, taskFragmentInfo);
container.clearPendingAppearedActivities();
if (container.isEmpty()) {
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
}
break;
@@ -1000,7 +1007,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@GuardedBy("mLock")
void onTaskFragmentAppearEmptyTimeout(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container) {
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
}
@@ -1566,7 +1574,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// (not resumed yet).
if (isOnCreated || primaryActivity.isResumed()) {
// Only set trigger type if the launch happens in foreground.
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_OPEN);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_OPEN);
return null;
}
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1594,7 +1603,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return false;
}
- mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
+ mTransactionManager.getCurrentTransactionRecord()
+ .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
mPresenter.cleanupContainer(wct, splitContainer.getSecondaryContainer(),
false /* shouldFinishDependent */);
return true;
@@ -1894,7 +1904,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
synchronized (mLock) {
final TransactionRecord transactionRecord = mTransactionManager
.startNewTransaction();
- transactionRecord.setOriginType(TRANSIT_OPEN);
+ transactionRecord.setOriginType(TASK_FRAGMENT_TRANSIT_OPEN);
SplitController.this.onActivityCreated(transactionRecord.getTransaction(),
activity);
// The WCT should be applied and merged to the activity launch transition.
@@ -1983,7 +1993,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
synchronized (mLock) {
final TransactionRecord transactionRecord = mTransactionManager
.startNewTransaction();
- transactionRecord.setOriginType(TRANSIT_OPEN);
+ transactionRecord.setOriginType(TASK_FRAGMENT_TRANSIT_OPEN);
final WindowContainerTransaction wct = transactionRecord.getTransaction();
final TaskFragmentContainer launchedInTaskFragment;
if (launchingActivity != null) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TransactionManager.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TransactionManager.java
index 0071fea41aa8..396956e56bb5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TransactionManager.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TransactionManager.java
@@ -16,12 +16,12 @@
package androidx.window.extensions.embedding;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_NONE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_NONE;
import android.os.IBinder;
-import android.view.WindowManager.TransitionType;
import android.window.TaskFragmentOrganizer;
+import android.window.TaskFragmentOrganizer.TaskFragmentTransitionType;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -122,8 +122,8 @@ class TransactionManager {
* @see #setOriginType(int)
* @see #getTransactionTransitionType()
*/
- @TransitionType
- private int mOriginType = TRANSIT_NONE;
+ @TaskFragmentTransitionType
+ private int mOriginType = TASK_FRAGMENT_TRANSIT_NONE;
TransactionRecord(@Nullable IBinder taskFragmentTransactionToken) {
mTaskFragmentTransactionToken = taskFragmentTransactionToken;
@@ -136,12 +136,12 @@ class TransactionManager {
}
/**
- * Sets the {@link TransitionType} that triggers this transaction. If there are multiple
- * calls, only the first call will be respected as the "origin" type.
+ * Sets the {@link TaskFragmentTransitionType} that triggers this transaction. If there are
+ * multiple calls, only the first call will be respected as the "origin" type.
*/
- void setOriginType(@TransitionType int type) {
+ void setOriginType(@TaskFragmentTransitionType int type) {
ensureCurrentTransaction();
- if (mOriginType != TRANSIT_NONE) {
+ if (mOriginType != TASK_FRAGMENT_TRANSIT_NONE) {
// Skip if the origin type has already been set.
return;
}
@@ -188,14 +188,16 @@ class TransactionManager {
}
/**
- * Gets the {@link TransitionType} that we will request transition with for the
+ * Gets the {@link TaskFragmentTransitionType} that we will request transition with for the
* current {@link WindowContainerTransaction}.
*/
@VisibleForTesting
- @TransitionType
+ @TaskFragmentTransitionType
int getTransactionTransitionType() {
- // Use TRANSIT_CHANGE as default if there is not opening/closing window.
- return mOriginType != TRANSIT_NONE ? mOriginType : TRANSIT_CHANGE;
+ // Use TASK_FRAGMENT_TRANSIT_CHANGE as default if there is not opening/closing window.
+ return mOriginType != TASK_FRAGMENT_TRANSIT_NONE
+ ? mOriginType
+ : TASK_FRAGMENT_TRANSIT_CHANGE;
}
}
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TransactionManagerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TransactionManagerTest.java
index 62006bd51399..459b6d2c31f9 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TransactionManagerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TransactionManagerTest.java
@@ -16,9 +16,9 @@
package androidx.window.extensions.embedding;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CLOSE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
@@ -86,27 +86,29 @@ public class TransactionManagerTest {
@Test
public void testSetTransactionOriginType() {
- // Return TRANSIT_CHANGE if there is no trigger type set.
+ // Return TASK_FRAGMENT_TRANSIT_CHANGE if there is no trigger type set.
TransactionRecord transactionRecord = mTransactionManager.startNewTransaction();
- assertEquals(TRANSIT_CHANGE, transactionRecord.getTransactionTransitionType());
+ assertEquals(TASK_FRAGMENT_TRANSIT_CHANGE,
+ transactionRecord.getTransactionTransitionType());
// Return the first set type.
mTransactionManager.getCurrentTransactionRecord().abort();
transactionRecord = mTransactionManager.startNewTransaction();
- transactionRecord.setOriginType(TRANSIT_OPEN);
+ transactionRecord.setOriginType(TASK_FRAGMENT_TRANSIT_OPEN);
- assertEquals(TRANSIT_OPEN, transactionRecord.getTransactionTransitionType());
+ assertEquals(TASK_FRAGMENT_TRANSIT_OPEN, transactionRecord.getTransactionTransitionType());
- transactionRecord.setOriginType(TRANSIT_CLOSE);
+ transactionRecord.setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
- assertEquals(TRANSIT_OPEN, transactionRecord.getTransactionTransitionType());
+ assertEquals(TASK_FRAGMENT_TRANSIT_OPEN, transactionRecord.getTransactionTransitionType());
// Reset when #startNewTransaction().
transactionRecord.abort();
transactionRecord = mTransactionManager.startNewTransaction();
- assertEquals(TRANSIT_CHANGE, transactionRecord.getTransactionTransitionType());
+ assertEquals(TASK_FRAGMENT_TRANSIT_CHANGE,
+ transactionRecord.getTransactionTransitionType());
}
@Test
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 51de2e57b6b0..8b467041ed5f 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -22,8 +22,8 @@
<string name="pip_phone_settings" msgid="5468987116750491918">"ቅንብሮች"</string>
<string name="pip_phone_enter_split" msgid="7042877263880641911">"የተከፈለ ማያ ገጽን አስገባ"</string>
<string name="pip_menu_title" msgid="5393619322111827096">"ምናሌ"</string>
- <string name="pip_menu_accessibility_title" msgid="8129016817688656249">"የስዕል-ላይ-ስዕል ምናሌ"</string>
- <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> በስዕል-ላይ-ስዕል ውስጥ ነው"</string>
+ <string name="pip_menu_accessibility_title" msgid="8129016817688656249">"የሥዕል-ላይ-ሥዕል ምናሌ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> በሥዕል-ላይ-ሥዕል ውስጥ ነው"</string>
<string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ይህን ባህሪ እንዲጠቀም ካልፈለጉ ቅንብሮችን ለመክፈት መታ ያድርጉና ያጥፉት።"</string>
<string name="pip_play" msgid="3496151081459417097">"አጫውት"</string>
<string name="pip_pause" msgid="690688849510295232">"ባለበት አቁም"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings_tv.xml b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
index d64c051ecd23..a6be57889a4e 100644
--- a/libs/WindowManager/Shell/res/values-am/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="2576686079160402435">"ስዕል-ላይ-ስዕል"</string>
+ <string name="notification_channel_tv_pip" msgid="2576686079160402435">"ሥዕል-ላይ-ሥዕል"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ርዕስ የሌለው ፕሮግራም)"</string>
<string name="pip_close" msgid="2955969519031223530">"ዝጋ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ሙሉ ማያ ገጽ"</string>
@@ -25,7 +25,7 @@
<string name="pip_expand" msgid="1051966011679297308">"ዘርጋ"</string>
<string name="pip_collapse" msgid="3903295106641385962">"ሰብስብ"</string>
<string name="pip_edu_text" msgid="7930546669915337998">"ለመቆጣጠሪያዎች "<annotation icon="home_icon">"መነሻ"</annotation>"ን ሁለቴ ይጫኑ"</string>
- <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"የስዕል-ላይ-ስዕል ምናሌ።"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"የሥዕል-ላይ-ሥዕል ምናሌ።"</string>
<string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ወደ ግራ ውሰድ"</string>
<string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ወደ ቀኝ ውሰድ"</string>
<string name="a11y_action_pip_move_up" msgid="98502616918621959">"ወደ ላይ ውሰድ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 1f2ee77079bc..092331284f61 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -34,8 +34,7 @@
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"അൺസ്റ്റാഷ് ചെയ്യൽ"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"സ്‌ക്രീൻ വിഭജന മോഡിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
- <!-- no translation found for dock_multi_instances_not_supported_text (5242868470666346929) -->
- <skip />
+ <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ഈ ആപ്പ് ഒരു വിൻഡോയിൽ മാത്രമേ തുറക്കാനാകൂ."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്‌പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"രണ്ടാം ഡിസ്‌പ്ലേകളിൽ സമാരംഭിക്കുന്നതിനെ ആപ്പ് അനുവദിക്കുന്നില്ല."</string>
<string name="accessibility_divider" msgid="703810061635792791">"സ്പ്ലിറ്റ്-സ്ക്രീൻ ഡിവൈഡർ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 2039685ecc53..525f2ea043fc 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -34,8 +34,7 @@
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"திரைப் பிரிப்பு அம்சத்தில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"திரையைப் பிரிப்பதைப் ஆப்ஸ் ஆதரிக்கவில்லை."</string>
- <!-- no translation found for dock_multi_instances_not_supported_text (5242868470666346929) -->
- <skip />
+ <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"இந்த ஆப்ஸை 1 சாளரத்தில் மட்டுமே திறக்க முடியும்."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"இரண்டாம்நிலைத் திரைகளில் பயன்பாட்டைத் தொடங்க முடியாது."</string>
<string name="accessibility_divider" msgid="703810061635792791">"திரையைப் பிரிக்கும் பிரிப்பான்"</string>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index c6197c8a730b..23db2335ecc0 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -113,6 +113,6 @@
<bool name="config_dimNonImeAttachedSide">true</bool>
<!-- Components support to launch multiple instances into split-screen -->
- <string-array name="config_componentsSupportMultiInstancesSplit">
+ <string-array name="config_appsSupportMultiInstancesSplit">
</string-array>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index af13bf54f691..94aeb2beb1e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -346,7 +346,7 @@ public class SystemWindows {
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration newMergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
- int resizeMode) {}
+ boolean dragResizing) {}
@Override
public void insetsControlChanged(InsetsState insetsState,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 214b304df07c..c63419851f7f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -403,5 +403,10 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
}
return true;
}
+
+ @Override
+ public boolean onDoubleTapEvent(@NonNull MotionEvent e) {
+ return true;
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index c836b95ffab8..a9d3c9f154cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -74,7 +74,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
private boolean mShown;
private boolean mIsResizing;
- private final Rect mBounds = new Rect();
+ private final Rect mOldBounds = new Rect();
+ private final Rect mResizingBounds = new Rect();
private final Rect mTempRect = new Rect();
private ValueAnimator mFadeAnimator;
@@ -158,6 +159,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
mResizingIconView = null;
mIsResizing = false;
mShown = false;
+ mOldBounds.setEmpty();
+ mResizingBounds.setEmpty();
}
/** Showing resizing hint. */
@@ -170,13 +173,14 @@ public class SplitDecorManager extends WindowlessWindowManager {
if (!mIsResizing) {
mIsResizing = true;
- mBounds.set(newBounds);
+ mOldBounds.set(newBounds);
}
+ mResizingBounds.set(newBounds);
mOffsetX = offsetX;
mOffsetY = offsetY;
final boolean show =
- newBounds.width() > mBounds.width() || newBounds.height() > mBounds.height();
+ newBounds.width() > mOldBounds.width() || newBounds.height() > mOldBounds.height();
final boolean update = show != mShown;
if (update && mFadeAnimator != null && mFadeAnimator.isRunning()) {
// If we need to animate and animator still running, cancel it before we ensure both
@@ -193,8 +197,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
if (mGapBackgroundLeash == null && !immediately) {
final boolean isLandscape = newBounds.height() == sideBounds.height();
- final int left = isLandscape ? mBounds.width() : 0;
- final int top = isLandscape ? 0 : mBounds.height();
+ final int left = isLandscape ? mOldBounds.width() : 0;
+ final int top = isLandscape ? 0 : mOldBounds.height();
mGapBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
GAP_BACKGROUND_SURFACE_NAME, mSurfaceSession);
// Fill up another side bounds area.
@@ -272,6 +276,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
mIsResizing = false;
mOffsetX = 0;
mOffsetY = 0;
+ mOldBounds.setEmpty();
+ mResizingBounds.setEmpty();
if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
if (!mShown) {
// If fade-out animation is running, just add release callback to it.
@@ -303,8 +309,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
/** Screenshot host leash and attach on it if meet some conditions */
public void screenshotIfNeeded(SurfaceControl.Transaction t) {
- if (!mShown && mIsResizing) {
- mTempRect.set(mBounds);
+ if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+ mTempRect.set(mOldBounds);
mTempRect.offsetTo(0, 0);
mScreenshot = ScreenshotUtils.takeScreenshot(t, mHostLeash, mTempRect,
Integer.MAX_VALUE - 1);
@@ -315,7 +321,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
public void setScreenshotIfNeeded(SurfaceControl screenshot, SurfaceControl.Transaction t) {
if (screenshot == null || !screenshot.isValid()) return;
- if (!mShown && mIsResizing) {
+ if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
mScreenshot = screenshot;
t.reparent(screenshot, mHostLeash);
t.setLayer(screenshot, Integer.MAX_VALUE - 1);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 7eb01a79f14f..f5f3573252ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -40,6 +40,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArraySet;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.window.DisplayAreaInfo;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -329,15 +330,17 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- // Only do anything if we are in desktop mode and opening a task/app in freeform
+ // Only do anything if we are in desktop mode and opening/moving-to-front a task/app in
+ // freeform
if (!DesktopModeStatus.isActive(mContext)) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE,
"skip shell transition request: desktop mode not active");
return null;
}
- if (request.getType() != TRANSIT_OPEN) {
+ if (request.getType() != TRANSIT_OPEN && request.getType() != TRANSIT_TO_FRONT) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE,
- "skip shell transition request: only supports TRANSIT_OPEN");
+ "skip shell transition request: unsupported type %s",
+ WindowManager.transitTypeToString(request.getType()));
return null;
}
if (request.getTriggerTask() == null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 62bf5172e106..d93a9012c8f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -240,7 +240,7 @@ public class DragAndDropPolicy {
// Update launch options for the split side we are targeting.
position = leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
// Add some data for logging splitscreen once it is invoked
- mSplitScreen.logOnDroppedToSplit(position, mLoggerSessionId);
+ mSplitScreen.onDroppedToSplit(position, mLoggerSessionId);
}
final ClipDescription description = data.getDescription();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index e7ec15e70c11..89538cb394d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -16,9 +16,6 @@
package com.android.wm.shell.splitscreen;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
-
import android.content.Context;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
@@ -34,8 +31,6 @@ import com.android.wm.shell.common.SyncTransactionQueue;
* @see StageCoordinator
*/
class MainStage extends StageTaskListener {
- private static final String TAG = MainStage.class.getSimpleName();
-
private boolean mIsActive = false;
MainStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
@@ -52,15 +47,8 @@ class MainStage extends StageTaskListener {
void activate(WindowContainerTransaction wct, boolean includingTopTask) {
if (mIsActive) return;
- final WindowContainerToken rootToken = mRootTaskInfo.token;
if (includingTopTask) {
- wct.reparentTasks(
- null /* currentParent */,
- rootToken,
- CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES,
- true /* onTop */,
- true /* reparentTopOnly */);
+ reparentTopTask(wct);
}
mIsActive = true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 9329d021d007..ef70d9bd84ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,7 +18,6 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -98,7 +97,6 @@ import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -123,7 +121,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
public static final int EXIT_REASON_SCREEN_LOCKED = 7;
public static final int EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP = 8;
public static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
- public static final int EXIT_REASON_FULLSCREEN_SHORTCUT = 10;
+ public static final int EXIT_REASON_RECREATE_SPLIT = 10;
+ public static final int EXIT_REASON_FULLSCREEN_SHORTCUT = 11;
@IntDef(value = {
EXIT_REASON_UNKNOWN,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW,
@@ -135,6 +134,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
EXIT_REASON_SCREEN_LOCKED,
EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP,
EXIT_REASON_CHILD_TASK_ENTER_PIP,
+ EXIT_REASON_RECREATE_SPLIT,
EXIT_REASON_FULLSCREEN_SHORTCUT,
})
@Retention(RetentionPolicy.SOURCE)
@@ -171,7 +171,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
private final IconProvider mIconProvider;
private final Optional<RecentTasksController> mRecentTasksOptional;
private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler;
- private final String[] mMultiInstancesComponents;
+ private final String[] mAppsSupportMultiInstances;
@VisibleForTesting
StageCoordinator mStageCoordinator;
@@ -221,8 +221,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
// TODO(255224696): Remove the config once having a way for client apps to opt-in
// multi-instances split.
- mMultiInstancesComponents = mContext.getResources()
- .getStringArray(R.array.config_componentsSupportMultiInstancesSplit);
+ mAppsSupportMultiInstances = mContext.getResources()
+ .getStringArray(R.array.config_appsSupportMultiInstancesSplit);
}
@VisibleForTesting
@@ -261,8 +261,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator = stageCoordinator;
mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
shellInit.addInitCallback(this::onInit, this);
- mMultiInstancesComponents = mContext.getResources()
- .getStringArray(R.array.config_componentsSupportMultiInstancesSplit);
+ mAppsSupportMultiInstances = mContext.getResources()
+ .getStringArray(R.array.config_appsSupportMultiInstancesSplit);
}
public SplitScreen asSplitScreen() {
@@ -472,7 +472,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
*/
public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
@Nullable Bundle options, UserHandle user, @NonNull InstanceId instanceId) {
- mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
+ mStageCoordinator.onRequestToSplit(instanceId, ENTER_REASON_LAUNCHER);
startShortcut(packageName, shortcutId, position, options, user);
}
@@ -520,7 +520,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
*/
public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options, @NonNull InstanceId instanceId) {
- mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
+ mStageCoordinator.onRequestToSplit(instanceId, ENTER_REASON_LAUNCHER);
startIntent(intent, fillInIntent, position, options);
}
@@ -529,7 +529,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@SplitPosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter,
InstanceId instanceId) {
Intent fillInIntent = null;
- if (launchSameComponentAdjacently(pendingIntent, splitPosition, taskId)) {
+ if (launchSameAppAdjacently(pendingIntent, taskId)) {
if (supportMultiInstancesSplit(pendingIntent.getIntent().getComponent())) {
fillInIntent = new Intent();
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
@@ -556,7 +556,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
Intent fillInIntent = null;
- if (launchSameComponentAdjacently(pendingIntent, splitPosition, taskId)) {
+ if (launchSameAppAdjacently(pendingIntent, taskId)) {
if (supportMultiInstancesSplit(pendingIntent.getIntent().getComponent())) {
fillInIntent = new Intent();
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
@@ -578,7 +578,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
Intent fillInIntent1 = null;
Intent fillInIntent2 = null;
- if (launchSameComponentAdjacently(pendingIntent1, pendingIntent2)) {
+ if (launchSameAppAdjacently(pendingIntent1, pendingIntent2)) {
if (supportMultiInstancesSplit(pendingIntent1.getIntent().getComponent())) {
fillInIntent1 = new Intent();
fillInIntent1.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
@@ -613,7 +613,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
if (fillInIntent == null) fillInIntent = new Intent();
fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
- if (launchSameComponentAdjacently(intent, position, INVALID_TASK_ID)) {
+ if (launchSameAppAdjacently(position, intent)) {
final ComponentName launching = intent.getIntent().getComponent();
if (supportMultiInstancesSplit(launching)) {
// To prevent accumulating large number of instances in the background, reuse task
@@ -647,47 +647,52 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.startIntent(intent, fillInIntent, position, options);
}
- /** Returns {@code true} if it's launching the same component on both sides of the split. */
- private boolean launchSameComponentAdjacently(@Nullable PendingIntent pendingIntent,
- @SplitPosition int position, int taskId) {
- if (pendingIntent == null || pendingIntent.getIntent() == null) return false;
-
- final ComponentName launchingActivity = pendingIntent.getIntent().getComponent();
- if (launchingActivity == null) return false;
-
- if (taskId != INVALID_TASK_ID) {
- final ActivityManager.RunningTaskInfo taskInfo =
- mTaskOrganizer.getRunningTaskInfo(taskId);
- if (taskInfo != null) {
- return Objects.equals(taskInfo.baseIntent.getComponent(), launchingActivity);
- }
- return false;
+ @Nullable
+ private String getPackageName(Intent intent) {
+ if (intent == null || intent.getComponent() == null) {
+ return null;
}
+ return intent.getComponent().getPackageName();
+ }
- if (!isSplitScreenVisible()) {
- // Split screen is not yet activated, check if the current top running task is valid to
- // split together.
- final ActivityManager.RunningTaskInfo topRunningTask = mRecentTasksOptional
+ private boolean launchSameAppAdjacently(@SplitPosition int position,
+ PendingIntent pendingIntent) {
+ ActivityManager.RunningTaskInfo adjacentTaskInfo = null;
+ if (isSplitScreenVisible()) {
+ adjacentTaskInfo = getTaskInfo(SplitLayout.reversePosition(position));
+ } else {
+ adjacentTaskInfo = mRecentTasksOptional
.map(recentTasks -> recentTasks.getTopRunningTask()).orElse(null);
- if (topRunningTask != null && isValidToEnterSplitScreen(topRunningTask)) {
- return Objects.equals(topRunningTask.baseIntent.getComponent(), launchingActivity);
+ if (!isValidToEnterSplitScreen(adjacentTaskInfo)) {
+ return false;
}
+ }
+
+ if (adjacentTaskInfo == null) {
return false;
}
- // Compare to the adjacent side of the split to determine if this is launching the same
- // component adjacently.
- final ActivityManager.RunningTaskInfo pairedTaskInfo =
- getTaskInfo(SplitLayout.reversePosition(position));
- final ComponentName pairedActivity = pairedTaskInfo != null
- ? pairedTaskInfo.baseIntent.getComponent() : null;
- return Objects.equals(launchingActivity, pairedActivity);
+ final String targetPackageName = getPackageName(pendingIntent.getIntent());
+ final String adjacentPackageName = getPackageName(adjacentTaskInfo.baseIntent);
+ return targetPackageName != null && targetPackageName.equals(adjacentPackageName);
+ }
+
+ private boolean launchSameAppAdjacently(PendingIntent pendingIntent, int taskId) {
+ final ActivityManager.RunningTaskInfo adjacentTaskInfo =
+ mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (adjacentTaskInfo == null) {
+ return false;
+ }
+ final String targetPackageName = getPackageName(pendingIntent.getIntent());
+ final String adjacentPackageName = getPackageName(adjacentTaskInfo.baseIntent);
+ return targetPackageName != null && targetPackageName.equals(adjacentPackageName);
}
- private boolean launchSameComponentAdjacently(PendingIntent pendingIntent1,
+ private boolean launchSameAppAdjacently(PendingIntent pendingIntent1,
PendingIntent pendingIntent2) {
- return Objects.equals(pendingIntent1.getIntent().getComponent(),
- pendingIntent2.getIntent().getComponent());
+ final String targetPackageName = getPackageName(pendingIntent1.getIntent());
+ final String adjacentPackageName = getPackageName(pendingIntent2.getIntent());
+ return targetPackageName != null && targetPackageName.equals(adjacentPackageName);
}
@VisibleForTesting
@@ -695,9 +700,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
boolean supportMultiInstancesSplit(@Nullable ComponentName launching) {
if (launching == null) return false;
- final String componentName = launching.flattenToString();
- for (int i = 0; i < mMultiInstancesComponents.length; i++) {
- if (mMultiInstancesComponents[i].equals(componentName)) {
+ final String packageName = launching.getPackageName();
+ for (int i = 0; i < mAppsSupportMultiInstances.length; i++) {
+ if (mAppsSupportMultiInstances[i].equals(packageName)) {
return true;
}
}
@@ -781,10 +786,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return splitTasksLayer;
}
/**
- * Sets drag info to be logged when splitscreen is entered.
+ * Drop callback when splitscreen is entered.
*/
- public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
- mStageCoordinator.logOnDroppedToSplit(position, dragSessionId);
+ public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
+ mStageCoordinator.onDroppedToSplit(position, dragSessionId);
}
/**
@@ -812,6 +817,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return "APP_DOES_NOT_SUPPORT_MULTIWINDOW";
case EXIT_REASON_CHILD_TASK_ENTER_PIP:
return "CHILD_TASK_ENTER_PIP";
+ case EXIT_REASON_RECREATE_SPLIT:
+ return "RECREATE_SPLIT";
default:
return "unknown reason, reason int = " + exitReason;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
index 1016e1bcd66f..5483fa5d29f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -21,9 +21,11 @@ import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED_
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__UNKNOWN_ENTER;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__CHILD_TASK_ENTER_PIP;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__FULLSCREEN_SHORTCUT;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RECREATE_SPLIT;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__ROOT_TASK_VANISHED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
@@ -37,9 +39,11 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASO
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_FULLSCREEN_SHORTCUT;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RECREATE_SPLIT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ROOT_TASK_VANISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED;
@@ -182,6 +186,10 @@ public class SplitscreenEventLogger {
return SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
return SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
+ case EXIT_REASON_CHILD_TASK_ENTER_PIP:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__CHILD_TASK_ENTER_PIP;
+ case EXIT_REASON_RECREATE_SPLIT:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__RECREATE_SPLIT;
case EXIT_REASON_FULLSCREEN_SHORTCUT:
return SPLITSCREEN_UICHANGED__EXIT_REASON__FULLSCREEN_SHORTCUT;
case EXIT_REASON_UNKNOWN:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index da8dc8733ef5..602d0e6c0201 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -49,10 +49,11 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASO
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_MULTI_INSTANCE;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
-import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_FULLSCREEN_SHORTCUT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_FULLSCREEN_SHORTCUT;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RECREATE_SPLIT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ROOT_TASK_VANISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
@@ -199,7 +200,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// and exit, since exit itself can trigger a number of changes that update the stages.
private boolean mShouldUpdateRecents;
private boolean mExitSplitScreenOnHide;
- private boolean mIsDividerRemoteAnimating;
+ private boolean mIsSplitEntering;
+ private boolean mIsDropEntering;
private boolean mIsExiting;
/** The target stage to dismiss to when unlock after folded. */
@@ -347,10 +349,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return mSplitTransitions;
}
- boolean isSplitScreenVisible() {
+ public boolean isSplitScreenVisible() {
return mSideStageListener.mVisible && mMainStageListener.mVisible;
}
+ public boolean isSplitActive() {
+ return mMainStage.isActive();
+ }
+
+ boolean isSplitScreenRunningBackground() {
+ return !isSplitScreenVisible() && mMainStageListener.mHasChildren
+ && mSideStageListener.mHasChildren;
+ }
+
@StageType
int getStageOfTask(int taskId) {
if (mMainStage.containsTask(taskId)) {
@@ -373,11 +384,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
targetStage = mSideStage;
sideStagePosition = stagePosition;
} else {
- if (mMainStage.isActive()) {
+ if (isSplitScreenVisible()) {
// If the split screen is activated, retrieves target stage based on position.
targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
sideStagePosition = mSideStagePosition;
} else {
+ exitSplitIfBackground();
targetStage = mSideStage;
sideStagePosition = stagePosition;
}
@@ -673,6 +685,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Nullable PendingIntent mainPendingIntent, @Nullable Intent mainFillInIntent,
@Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio,
RemoteAnimationAdapter adapter, InstanceId instanceId) {
+ exitSplitIfBackground();
// Init divider first to make divider leash for remote animation target.
mSplitLayout.init();
mSplitLayout.setDivideRatio(splitRatio);
@@ -685,11 +698,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
- mIsDividerRemoteAnimating = true;
+ mIsSplitEntering = true;
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
- prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
+ if (isSplitScreenVisible()) {
+ mMainStage.evictAllChildren(evictWct);
+ mSideStage.evictAllChildren(evictWct);
+ }
IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@Override
@@ -769,7 +784,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void onRemoteAnimationFinishedOrCancelled(boolean cancel,
WindowContainerTransaction evictWct) {
- mIsDividerRemoteAnimating = false;
+ mIsSplitEntering = false;
mShouldUpdateRecents = true;
// If any stage has no child after animation finished, it means that split will display
// nothing, such status will happen if task and intent is same app but not support
@@ -781,6 +796,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitUnsupportedToast.show();
} else {
mSyncQueue.queue(evictWct);
+ mSyncQueue.runInSync(t -> {
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ });
}
}
@@ -815,7 +833,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
switch (stage) {
case STAGE_TYPE_UNDEFINED: {
if (position != SPLIT_POSITION_UNDEFINED) {
- if (mMainStage.isActive()) {
+ if (isSplitScreenVisible()) {
// Use the stage of the specified position
options = resolveStartStage(
position == mSideStagePosition ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN,
@@ -1045,7 +1063,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
});
mShouldUpdateRecents = false;
- mIsDividerRemoteAnimating = false;
+ mIsSplitEntering = false;
mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
@@ -1064,6 +1082,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.setSmallestScreenWidthDp(childrenToTop.mRootTaskInfo.token,
SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
}
+ wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
+ false /* reparentLeafTaskIfRelaunch */);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
t.setWindowCrop(mMainStage.mRootLeash, null)
@@ -1102,6 +1122,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
+ /** Exit split screen if it still running background */
+ public void exitSplitIfBackground() {
+ if (!isSplitScreenRunningBackground()) return;
+
+ exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
+ }
+
/**
* Overridden by child classes.
*/
@@ -1374,7 +1401,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
&& !ENABLE_SHELL_TRANSITIONS) {
// Clear the divider remote animating flag as the divider will be re-rendered to apply
// the new rotation config.
- mIsDividerRemoteAnimating = false;
+ mIsSplitEntering = false;
mSplitLayout.update(null /* t */);
onLayoutSizeChanged(mSplitLayout);
}
@@ -1423,6 +1450,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
});
}
+ void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) {
+ if (stageListener == mSideStageListener && isSplitScreenRunningBackground()) {
+ // Handle entring split case here if split already running background.
+ if (mIsDropEntering) {
+ mSplitLayout.resetDividerPosition();
+ } else {
+ mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mMainStage.evictAllChildren(wct);
+ mSideStage.evictOtherChildren(wct, taskId);
+ mMainStage.reparentTopTask(wct);
+ updateWindowBounds(mSplitLayout, wct);
+ wct.reorder(mRootTaskInfo.token, true);
+
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> {
+ if (mIsDropEntering) {
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ mIsDropEntering = false;
+ } else {
+ mSplitLayout.flingDividerToCenter();
+ }
+ });
+ }
+ }
+
private void onRootTaskVanished() {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (mRootTaskInfo != null) {
@@ -1441,20 +1495,20 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
if (!mainStageVisible) {
+ wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
+ true /* setReparentLeafTaskIfRelaunch */);
// Both stages are not visible, check if it needs to dismiss split screen.
- if (mExitSplitScreenOnHide
- // Don't dismiss split screen when both stages are not visible due to sleeping
- // display.
- || (!mMainStage.mRootTaskInfo.isSleeping
- && !mSideStage.mRootTaskInfo.isSleeping)) {
+ if (mExitSplitScreenOnHide) {
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
}
+ } else {
+ wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
+ false /* setReparentLeafTaskIfRelaunch */);
}
-
+ mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
- t.setVisibility(mSideStage.mRootLeash, sideStageVisible)
- .setVisibility(mMainStage.mRootLeash, mainStageVisible);
setDividerVisibility(mainStageVisible, t);
});
}
@@ -1479,7 +1533,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDividerVisible = visible;
sendSplitVisibilityChanged();
- if (mIsDividerRemoteAnimating) {
+ if (mIsSplitEntering) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
" Skip animating divider bar due to it's remote animating.");
return;
@@ -1499,7 +1553,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
" Skip animating divider bar due to divider leash not ready.");
return;
}
- if (mIsDividerRemoteAnimating) {
+ if (mIsSplitEntering) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
" Skip animating divider bar due to it's remote animating.");
return;
@@ -1555,26 +1609,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!hasChildren && !mIsExiting && mMainStage.isActive()) {
if (isSideStage && mMainStageListener.mVisible) {
// Exit to main stage if side stage no longer has children.
- if (ENABLE_SHELL_TRANSITIONS) {
- exitSplitScreen(mMainStage, EXIT_REASON_APP_FINISHED);
- } else {
- mSplitLayout.flingDividerToDismiss(
- mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT,
- EXIT_REASON_APP_FINISHED);
- }
+ mSplitLayout.flingDividerToDismiss(
+ mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT,
+ EXIT_REASON_APP_FINISHED);
} else if (!isSideStage && mSideStageListener.mVisible) {
// Exit to side stage if main stage no longer has children.
- if (ENABLE_SHELL_TRANSITIONS) {
- exitSplitScreen(mSideStage, EXIT_REASON_APP_FINISHED);
- } else {
- mSplitLayout.flingDividerToDismiss(
- mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT,
- EXIT_REASON_APP_FINISHED);
- }
+ mSplitLayout.flingDividerToDismiss(
+ mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT,
+ EXIT_REASON_APP_FINISHED);
+ } else if (isSplitScreenRunningBackground()) {
+ // Do not exit to any stage due to running background.
+ exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED);
}
} else if (isSideStage && hasChildren && !mMainStage.isActive()) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
mSplitLayout.init();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
if (mLogger.isEnterRequestedByDrag()) {
prepareEnterSplitScreen(wct);
} else {
@@ -1589,8 +1639,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
- if (mLogger.isEnterRequestedByDrag()) {
+ if (mIsDropEntering) {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ mIsDropEntering = false;
} else {
mShowDecorImmediately = true;
mSplitLayout.flingDividerToCenter();
@@ -1945,10 +1996,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
- public boolean isSplitActive() {
- return mMainStage.isActive();
- }
-
@Override
public void mergeAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
@@ -2304,11 +2351,29 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
/**
* Sets drag info to be logged when splitscreen is next entered.
*/
- public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
+ public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
+ if (!isSplitScreenVisible()) {
+ mIsDropEntering = true;
+ }
+ if (isSplitScreenRunningBackground()) {
+ // Split running background, log exit first and start new enter request.
+ logExit(EXIT_REASON_RECREATE_SPLIT);
+ }
mLogger.enterRequestedByDrag(position, dragSessionId);
}
/**
+ * Sets info to be logged when splitscreen is next entered.
+ */
+ public void onRequestToSplit(InstanceId sessionId, int enterReason) {
+ if (isSplitScreenRunningBackground()) {
+ // Split running background, log exit first and start new enter request.
+ logExit(EXIT_REASON_RECREATE_SPLIT);
+ }
+ mLogger.enterRequested(sessionId, enterReason);
+ }
+
+ /**
* Logs the exit of splitscreen.
*/
private void logExit(@ExitReason int exitReason) {
@@ -2343,6 +2408,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
+ public void onChildTaskAppeared(int taskId) {
+ StageCoordinator.this.onChildTaskAppeared(this, taskId);
+ }
+
+ @Override
public void onStatusChanged(boolean visible, boolean hasChildren) {
if (!mHasRootTask) return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 8a52c8750ba6..a841b7f96d3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
+import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -69,6 +70,8 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
public interface StageListenerCallbacks {
void onRootTaskAppeared();
+ void onChildTaskAppeared(int taskId);
+
void onStatusChanged(boolean visible, boolean hasChildren);
void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
@@ -185,6 +188,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
// Status is managed/synchronized by the transition lifecycle.
return;
}
+ mCallbacks.onChildTaskAppeared(taskId);
sendStatusChanged();
} else {
throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
@@ -338,6 +342,14 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
}
+ void evictOtherChildren(WindowContainerTransaction wct, int taskId) {
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
+ final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
+ if (taskId == taskInfo.taskId) continue;
+ wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ }
+ }
+
void evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct) {
final SparseArray<ActivityManager.RunningTaskInfo> toBeEvict = mChildrenTaskInfo.clone();
for (int i = 0; i < apps.length; i++) {
@@ -360,6 +372,12 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
}
+ void reparentTopTask(WindowContainerTransaction wct) {
+ wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token,
+ CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES,
+ true /* onTop */, true /* reparentTopOnly */);
+ }
+
void resetBounds(WindowContainerTransaction wct) {
wct.setBounds(mRootTaskInfo.token, null);
wct.setAppBounds(mRootTaskInfo.token, null);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 9d6711f42efe..65da757b1396 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -239,7 +239,7 @@ public class TaskSnapshotWindow {
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int seqId,
- int resizeMode) {
+ boolean dragResizing) {
final TaskSnapshotWindow snapshot = mOuter.get();
if (snapshot == null) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 3cba92956f95..a2d7bc43653a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -111,7 +111,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitActive()) {
+ if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitScreenVisible()) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request while "
+ "Split-Screen is active, so treat it as Mixed.");
if (request.getRemoteTransition() != null) {
diff --git a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
index 59d9104fb5ba..fac04614d945 100644
--- a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
@@ -19,6 +19,8 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.wm.shell.tests">
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.mock" />
<uses-library android:name="android.test.runner" />
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index b3c9e238a614..707c04948b6f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
@@ -334,10 +335,10 @@ public class DesktopModeControllerTest extends ShellTestCase {
}
@Test
- public void testHandleTransitionRequest_notTransitOpen_returnsNull() {
+ public void testHandleTransitionRequest_unsupportedTransit_returnsNull() {
WindowContainerTransaction wct = mController.handleRequest(
new Binder(),
- new TransitionRequestInfo(TRANSIT_TO_FRONT, null /* trigger */, null /* remote */));
+ new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
assertThat(wct).isNull();
}
@@ -352,7 +353,7 @@ public class DesktopModeControllerTest extends ShellTestCase {
}
@Test
- public void testHandleTransitionRequest_returnsWct() {
+ public void testHandleTransitionRequest_taskOpen_returnsWct() {
RunningTaskInfo trigger = new RunningTaskInfo();
trigger.token = new MockToken().mToken;
trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -362,6 +363,17 @@ public class DesktopModeControllerTest extends ShellTestCase {
assertThat(wct).isNotNull();
}
+ @Test
+ public void testHandleTransitionRequest_taskToFront_returnsWct() {
+ RunningTaskInfo trigger = new RunningTaskInfo();
+ trigger.token = new MockToken().mToken;
+ trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ WindowContainerTransaction wct = mController.handleRequest(
+ mock(IBinder.class),
+ new TransitionRequestInfo(TRANSIT_TO_FRONT, trigger, null /* remote */));
+ assertThat(wct).isNotNull();
+ }
+
private DesktopModeController createController() {
return new DesktopModeController(mContext, mShellInit, mShellController,
mShellTaskOrganizer, mRootTaskDisplayAreaOrganizer, mTransitions,
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 277955e88dfe..6affc6a81685 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -82,7 +82,7 @@ bool Properties::isolatedProcess = false;
int Properties::contextPriority = 0;
float Properties::defaultSdrWhitePoint = 200.f;
-bool Properties::useHintManager = true;
+bool Properties::useHintManager = false;
int Properties::targetCpuTimePercentage = 70;
bool Properties::enableWebViewOverlays = true;
@@ -142,7 +142,7 @@ bool Properties::load() {
runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false);
- useHintManager = base::GetBoolProperty(PROPERTY_USE_HINT_MANAGER, true);
+ useHintManager = base::GetBoolProperty(PROPERTY_USE_HINT_MANAGER, false);
targetCpuTimePercentage = base::GetIntProperty(PROPERTY_TARGET_CPU_TIME_PERCENTAGE, 70);
if (targetCpuTimePercentage <= 0 || targetCpuTimePercentage > 100) targetCpuTimePercentage = 70;
diff --git a/libs/hwui/jni/Mesh.cpp b/libs/hwui/jni/Mesh.cpp
index 7c732d7fdcf2..7b9a93fe0fba 100644
--- a/libs/hwui/jni/Mesh.cpp
+++ b/libs/hwui/jni/Mesh.cpp
@@ -37,16 +37,6 @@ sk_sp<SkMesh::IndexBuffer> genIndexBuffer(JNIEnv* env, jobject buffer, int size,
return indexBuffer;
}
-// TODO(b/260252882): undefine SK_LEGACY_MESH_MAKE and remove this.
-template <typename T>
-SkMesh get_mesh_from_result(T&& result) {
-#ifdef SK_LEGACY_MESH_MAKE
- return result;
-#else
- return result.mesh;
-#endif
-}
-
static jlong make(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobject vertexBuffer,
jboolean isDirect, jint vertexCount, jint vertexOffset, jint left, jint top,
jint right, jint bottom) {
@@ -54,8 +44,9 @@ static jlong make(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobject verte
sk_sp<SkMesh::VertexBuffer> skVertexBuffer =
genVertexBuffer(env, vertexBuffer, vertexCount * skMeshSpec->stride(), isDirect);
auto skRect = SkRect::MakeLTRB(left, top, right, bottom);
- auto mesh = get_mesh_from_result(SkMesh::Make(skMeshSpec, SkMesh::Mode(mode), skVertexBuffer,
- vertexCount, vertexOffset, nullptr, skRect));
+ auto mesh = SkMesh::Make(skMeshSpec, SkMesh::Mode(mode), skVertexBuffer, vertexCount,
+ vertexOffset, nullptr, skRect)
+ .mesh;
auto meshPtr = std::make_unique<MeshWrapper>(MeshWrapper{mesh, MeshUniformBuilder(skMeshSpec)});
return reinterpret_cast<jlong>(meshPtr.release());
}
@@ -70,9 +61,10 @@ static jlong makeIndexed(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobjec
sk_sp<SkMesh::IndexBuffer> skIndexBuffer =
genIndexBuffer(env, indexBuffer, indexCount * gIndexByteSize, isIndexDirect);
auto skRect = SkRect::MakeLTRB(left, top, right, bottom);
- auto mesh = get_mesh_from_result(SkMesh::MakeIndexed(
- skMeshSpec, SkMesh::Mode(mode), skVertexBuffer, vertexCount, vertexOffset,
- skIndexBuffer, indexCount, indexOffset, nullptr, skRect));
+ auto mesh = SkMesh::MakeIndexed(skMeshSpec, SkMesh::Mode(mode), skVertexBuffer, vertexCount,
+ vertexOffset, skIndexBuffer, indexCount, indexOffset, nullptr,
+ skRect)
+ .mesh;
auto meshPtr = std::make_unique<MeshWrapper>(MeshWrapper{mesh, MeshUniformBuilder(skMeshSpec)});
return reinterpret_cast<jlong>(meshPtr.release());
}
@@ -81,15 +73,17 @@ static void updateMesh(JNIEnv* env, jobject, jlong meshWrapper, jboolean indexed
auto wrapper = reinterpret_cast<MeshWrapper*>(meshWrapper);
auto mesh = wrapper->mesh;
if (indexed) {
- wrapper->mesh = get_mesh_from_result(SkMesh::MakeIndexed(
- sk_ref_sp(mesh.spec()), mesh.mode(), sk_ref_sp(mesh.vertexBuffer()),
- mesh.vertexCount(), mesh.vertexOffset(), sk_ref_sp(mesh.indexBuffer()),
- mesh.indexCount(), mesh.indexOffset(), wrapper->builder.fUniforms, mesh.bounds()));
+ wrapper->mesh = SkMesh::MakeIndexed(sk_ref_sp(mesh.spec()), mesh.mode(),
+ sk_ref_sp(mesh.vertexBuffer()), mesh.vertexCount(),
+ mesh.vertexOffset(), sk_ref_sp(mesh.indexBuffer()),
+ mesh.indexCount(), mesh.indexOffset(),
+ wrapper->builder.fUniforms, mesh.bounds())
+ .mesh;
} else {
- wrapper->mesh = get_mesh_from_result(
- SkMesh::Make(sk_ref_sp(mesh.spec()), mesh.mode(), sk_ref_sp(mesh.vertexBuffer()),
- mesh.vertexCount(), mesh.vertexOffset(), wrapper->builder.fUniforms,
- mesh.bounds()));
+ wrapper->mesh = SkMesh::Make(sk_ref_sp(mesh.spec()), mesh.mode(),
+ sk_ref_sp(mesh.vertexBuffer()), mesh.vertexCount(),
+ mesh.vertexOffset(), wrapper->builder.fUniforms, mesh.bounds())
+ .mesh;
}
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9b81c09f5c5b..3619d3ac5253 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -195,6 +195,21 @@ public class LocationManager {
public static final String GPS_PROVIDER = "gps";
/**
+ * Standard name of the GNSS hardware location provider.
+ *
+ * <p>This provider is similar to {@link LocationManager#GPS_PROVIDER}, but it directly uses the
+ * HAL GNSS implementation and doesn't go through any provider overrides that may exist. This
+ * provider will only be available when the GPS_PROVIDER is overridden with a proxy using {@link
+ * android.location.provider.LocationProviderBase#ACTION_GNSS_PROVIDER}, and is intended only
+ * for use internally by the location provider system.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
+
+ /**
* A special location provider for receiving locations without actively initiating a location
* fix. This location provider is always present.
*
diff --git a/location/java/android/location/provider/LocationProviderBase.java b/location/java/android/location/provider/LocationProviderBase.java
index 5acec79a2d3b..18672b7fe10d 100644
--- a/location/java/android/location/provider/LocationProviderBase.java
+++ b/location/java/android/location/provider/LocationProviderBase.java
@@ -104,8 +104,6 @@ public abstract class LocationProviderBase {
/**
* The action the wrapping service should have in its intent filter to implement the
* {@link android.location.LocationManager#GPS_PROVIDER}.
- *
- * @hide
*/
public static final String ACTION_GNSS_PROVIDER =
"android.location.provider.action.GNSS_PROVIDER";
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 3b30b1d89268..5a72b0be3405 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -89,6 +89,8 @@ public final class AudioDeviceInfo {
public static final int TYPE_USB_ACCESSORY = 12;
/**
* A device type describing the audio device associated with a dock.
+ * Starting at API 34, this device type only represents digital docks, while docks with an
+ * analog connection are represented with {@link #TYPE_DOCK_ANALOG}.
* @see #TYPE_DOCK_ANALOG
*/
public static final int TYPE_DOCK = 13;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index ae0d45ffca24..3ed2c4b6ebc7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -8518,6 +8518,221 @@ public class AudioManager {
}
}
+ //====================================================================
+ // Preferred mixer attributes
+
+ /**
+ * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixe
+ * attributes via {@link #setPreferredMixerAttributes(
+ * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}.
+ * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes, the
+ * returned list may be empty when devices do not allow dynamic configuration.
+ *
+ * @param device the device to query
+ * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes
+ * for the given device.
+ * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
+ */
+ @NonNull
+ public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) {
+ Objects.requireNonNull(device);
+ List<AudioMixerAttributes> mixerAttrs = new ArrayList<>();
+ return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs)
+ == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>();
+ }
+
+ /**
+ * Configures the mixer attributes for a particular {@link AudioAttributes} over a given
+ * {@link AudioDeviceInfo}.
+ * <p>When constructing an {@link AudioMixerAttributes} for setting preferred mixer attributes,
+ * the mixer format must be constructed from an {@link AudioProfile} that can be used to set
+ * preferred mixer attributes.
+ * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the
+ * same uid is routed to the given audio device when calling this API, the output mixer/stream
+ * will be configured with the values previously set via this API.
+ * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)}
+ * to cancel setting mixer attributes for this {@link AudioAttributes}.
+ *
+ * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
+ * Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When
+ * playing audio targeted at the given device, use the same attributes for
+ * playback.
+ * @param device the device to be routed. Currently, only USB device will be allowed.
+ * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the
+ * given device, use the same {@link AudioFormat} for both playback
+ * and the mixer attributes.
+ * @return true only if the preferred mixer attributes are set successfully.
+ * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
+ * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes,
+ @NonNull AudioDeviceInfo device,
+ @NonNull AudioMixerAttributes mixerAttributes) {
+ Objects.requireNonNull(attributes);
+ Objects.requireNonNull(device);
+ Objects.requireNonNull(mixerAttributes);
+ try {
+ final int status = getService().setPreferredMixerAttributes(
+ attributes, device.getId(), mixerAttributes);
+ return status == AudioSystem.SUCCESS;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns current preferred mixer attributes that is set via
+ * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
+ *
+ * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
+ * @param device the expected routing device
+ * @return the preferred mixer attributes, which will be null when no preferred mixer attributes
+ * have been set, or when they have been cleared.
+ * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
+ * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
+ */
+ @Nullable
+ public AudioMixerAttributes getPreferredMixerAttributes(
+ @NonNull AudioAttributes attributes,
+ @NonNull AudioDeviceInfo device) {
+ Objects.requireNonNull(attributes);
+ Objects.requireNonNull(device);
+ List<AudioMixerAttributes> mixerAttrList = new ArrayList<>();
+ int ret = AudioSystem.getPreferredMixerAttributes(
+ attributes, device.getId(), mixerAttrList);
+ if (ret == AudioSystem.SUCCESS) {
+ return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0);
+ } else {
+ Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret);
+ return null;
+ }
+ }
+
+ /**
+ * Clears the current preferred mixer attributes that were previously set via
+ * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
+ *
+ * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared.
+ * @param device the expected routing device
+ * @return true only if the preferred mixer attributes are removed successfully.
+ * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
+ * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ public boolean clearPreferredMixerAttributes(
+ @NonNull AudioAttributes attributes,
+ @NonNull AudioDeviceInfo device) {
+ Objects.requireNonNull(attributes);
+ Objects.requireNonNull(device);
+ try {
+ final int status = getService().clearPreferredMixerAttributes(
+ attributes, device.getId());
+ return status == AudioSystem.SUCCESS;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Interface to be notified of changes in the preferred mixer attributes.
+ * <p>Note that this listener will only be invoked whenever
+ * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
+ * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device
+ * disconnection causes a change in preferred mixer attributes.
+ * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
+ * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
+ */
+ public interface OnPreferredMixerAttributesChangedListener {
+ /**
+ * Called on the listener to indicate that the preferred mixer attributes for the audio
+ * attributes over the given device has changed.
+ *
+ * @param attributes the audio attributes for playback
+ * @param device the targeted device
+ * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for
+ * preferred mixer attributes or null if preferred mixer attributes
+ * is cleared
+ */
+ void onPreferredMixerAttributesChanged(
+ @NonNull AudioAttributes attributes,
+ @NonNull AudioDeviceInfo device,
+ @Nullable AudioMixerAttributes mixerAttributes);
+ }
+
+ /**
+ * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the
+ * {@link PreferredMixerAttributesDispatcherStub}.
+ */
+ private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener>
+ mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager();
+
+ /**
+ * Adds a listener for being notified of changes to the preferred mixer attributes.
+ * @param executor the executor to execute the callback
+ * @param listener the listener to be notified of changes in the preferred mixer attributes.
+ */
+ public void addOnPreferredMixerAttributesChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnPreferredMixerAttributesChangedListener listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ mPrefMixerAttributesListenerMgr.addListener(executor, listener,
+ "addOnPreferredMixerAttributesChangedListener",
+ () -> new PreferredMixerAttributesDispatcherStub());
+ }
+
+ /**
+ * Removes a previously added listener of changes to the preferred mixer attributes.
+ * @param listener the listener to be notified of changes in the preferred mixer attributes,
+ * which were added via {@link #addOnPreferredMixerAttributesChangedListener(
+ * Executor, OnPreferredMixerAttributesChangedListener)}.
+ */
+ public void removeOnPreferredMixerAttributesChangedListener(
+ @NonNull OnPreferredMixerAttributesChangedListener listener) {
+ Objects.requireNonNull(listener);
+ mPrefMixerAttributesListenerMgr.removeListener(listener,
+ "removeOnPreferredMixerAttributesChangedListener");
+ }
+
+ private final class PreferredMixerAttributesDispatcherStub
+ extends IPreferredMixerAttributesDispatcher.Stub
+ implements CallbackUtil.DispatcherStub {
+
+ @Override
+ public void register(boolean register) {
+ try {
+ if (register) {
+ getService().registerPreferredMixerAttributesDispatcher(this);
+ } else {
+ getService().unregisterPreferredMixerAttributesDispatcher(this);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr,
+ int deviceId,
+ @Nullable AudioMixerAttributes mixerAttr) {
+ // TODO: If the device is disconnected, we may not be able to find the device with
+ // given device id. We need a better to carry the device information via binder.
+ AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS);
+ if (device == null) {
+ Log.d(TAG, "Drop preferred mixer attributes changed as the device("
+ + deviceId + ") is disconnected");
+ return;
+ }
+ mPrefMixerAttributesListenerMgr.callListeners(
+ (listener) -> listener.onPreferredMixerAttributesChanged(
+ attr, device, mixerAttr));
+ }
+ }
+
+ //====================================================================
+ // Mute await connection
+
private final Object mMuteAwaitConnectionListenerLock = new Object();
@GuardedBy("mMuteAwaitConnectionListenerLock")
diff --git a/media/java/android/media/AudioMixerAttributes.aidl b/media/java/android/media/AudioMixerAttributes.aidl
new file mode 100644
index 000000000000..0d9badde8d25
--- /dev/null
+++ b/media/java/android/media/AudioMixerAttributes.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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.media;
+
+parcelable AudioMixerAttributes;
diff --git a/media/java/android/media/AudioMixerAttributes.java b/media/java/android/media/AudioMixerAttributes.java
new file mode 100644
index 000000000000..3856da6e9446
--- /dev/null
+++ b/media/java/android/media/AudioMixerAttributes.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class to represent the attributes of the audio mixer: its format, which represents by an
+ * {@link AudioFormat} object and mixer behavior.
+ */
+public final class AudioMixerAttributes implements Parcelable {
+
+ /**
+ * Constant indicating the audio mixer behavior will follow the default platform behavior, which
+ * is mixing all audio sources in the mixer.
+ */
+ public static final int MIXER_BEHAVIOR_DEFAULT = 0;
+
+ /**
+ * Constant indicating the audio mixer behavior is bit-perfect, which indicates there will
+ * not be mixing happen, the audio data will be sent as is down to the HAL.
+ */
+ public static final int MIXER_BEHAVIOR_BIT_PERFECT = 1;
+
+ /** @hide */
+ @IntDef(flag = false, prefix = "MIXER_BEHAVIOR_", value = {
+ MIXER_BEHAVIOR_DEFAULT,
+ MIXER_BEHAVIOR_BIT_PERFECT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MixerBehavior {}
+
+ private final AudioFormat mFormat;
+ private final @MixerBehavior int mMixerBehavior;
+
+ /**
+ * Constructor from {@link AudioFormat} and mixer behavior
+ */
+ AudioMixerAttributes(AudioFormat format, @MixerBehavior int mixerBehavior) {
+ mFormat = format;
+ mMixerBehavior = mixerBehavior;
+ }
+
+ /**
+ * Return the format of the audio mixer. The format is an {@link AudioFormat} object, which
+ * includes encoding format, sample rate and channel mask or channel index mask.
+ * @return the format of the audio mixer.
+ */
+ @NonNull
+ public AudioFormat getFormat() {
+ return mFormat;
+ }
+
+ /**
+ * Returns the mixer behavior for this set of mixer attributes.
+ *
+ * @return the mixer behavior
+ */
+ public @MixerBehavior int getMixerBehavior() {
+ return mMixerBehavior;
+ }
+
+ /**
+ * Builder class for {@link AudioMixerAttributes} objects.
+ */
+ public static final class Builder {
+ private final AudioFormat mFormat;
+ private int mMixerBehavior = MIXER_BEHAVIOR_DEFAULT;
+
+ /**
+ * Constructs a new Builder with the defaults.
+ *
+ * @param format the {@link AudioFormat} for the audio mixer.
+ */
+ public Builder(@NonNull AudioFormat format) {
+ Objects.requireNonNull(format);
+ mFormat = format;
+ }
+
+ /**
+ * Combines all attributes that have been set and returns a new {@link AudioMixerAttributes}
+ * object.
+ * @return a new {@link AudioMixerAttributes} object
+ */
+ public @NonNull AudioMixerAttributes build() {
+ AudioMixerAttributes ama = new AudioMixerAttributes(mFormat, mMixerBehavior);
+ return ama;
+ }
+
+ /**
+ * Sets the mixer behavior for the audio mixer
+ * @param mixerBehavior must be {@link #MIXER_BEHAVIOR_DEFAULT} or
+ * {@link #MIXER_BEHAVIOR_BIT_PERFECT}.
+ * @return the same Builder instance.
+ */
+ public @NonNull Builder setMixerBehavior(@MixerBehavior int mixerBehavior) {
+ switch (mixerBehavior) {
+ case MIXER_BEHAVIOR_DEFAULT:
+ case MIXER_BEHAVIOR_BIT_PERFECT:
+ mMixerBehavior = mixerBehavior;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid mixer behavior " + mixerBehavior);
+ }
+ return this;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFormat, mMixerBehavior);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ AudioMixerAttributes that = (AudioMixerAttributes) o;
+ return (mFormat.equals(that.mFormat)
+ && (mMixerBehavior == that.mMixerBehavior));
+ }
+
+ private String mixerBehaviorToString(@MixerBehavior int mixerBehavior) {
+ switch (mixerBehavior) {
+ case MIXER_BEHAVIOR_DEFAULT:
+ return "default";
+ case MIXER_BEHAVIOR_BIT_PERFECT:
+ return "bit-perfect";
+ default:
+ return "unknown";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new String("AudioMixerAttributes:"
+ + " format:" + mFormat.toString()
+ + " mixer behavior:" + mixerBehaviorToString(mMixerBehavior));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mFormat, flags);
+ dest.writeInt(mMixerBehavior);
+ }
+
+ private AudioMixerAttributes(@NonNull Parcel in) {
+ mFormat = in.readParcelable(AudioFormat.class.getClassLoader(), AudioFormat.class);
+ mMixerBehavior = in.readInt();
+ }
+
+ public static final @NonNull Parcelable.Creator<AudioMixerAttributes> CREATOR =
+ new Parcelable.Creator<AudioMixerAttributes>() {
+ /**
+ * Rebuilds an AudioMixerAttributes previously stored with writeToParcel().
+ * @param p Parcel object to read the AudioMixerAttributes from
+ * @return a new AudioMixerAttributes created from the data in the parcel
+ */
+ public AudioMixerAttributes createFromParcel(Parcel p) {
+ return new AudioMixerAttributes(p);
+ }
+
+ public AudioMixerAttributes[] newArray(int size) {
+ return new AudioMixerAttributes[size];
+ }
+ };
+}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index fb643507f037..3e0d657588e5 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -2260,11 +2260,17 @@ public class AudioSystem
/**
* @hide
- * Register the sound dose callback with the audio server.
+ * Register the sound dose callback with the audio server and returns the binder to the
+ * ISoundDose interface.
*
- * @return {@link #SUCCESS} if the callback was registered successfully.
+ * @return ISoundDose interface with registered callback.
*/
- public static native int registerSoundDoseCallback(ISoundDoseCallback callback);
+ @Nullable
+ public static ISoundDose getSoundDoseInterface(ISoundDoseCallback callback) {
+ return ISoundDose.Stub.asInterface(nativeGetSoundDose(callback));
+ }
+
+ private static native IBinder nativeGetSoundDose(ISoundDoseCallback callback);
/**
* @hide
@@ -2434,4 +2440,40 @@ public class AudioSystem
* Keep in sync with core/jni/android_media_DeviceCallback.h.
*/
final static int NATIVE_EVENT_ROUTING_CHANGE = 1000;
+
+ /**
+ * @hide
+ * Query the mixer attributes that can be set as preferred mixer attributes for the given
+ * device.
+ */
+ public static native int getSupportedMixerAttributes(
+ int deviceId, @NonNull List<AudioMixerAttributes> mixerAttrs);
+
+ /**
+ * @hide
+ * Set preferred mixer attributes for a given device when playing particular
+ * audio attributes.
+ */
+ public static native int setPreferredMixerAttributes(
+ @NonNull AudioAttributes attributes,
+ int portId,
+ int uid,
+ @NonNull AudioMixerAttributes mixerAttributes);
+
+ /**
+ * @hide
+ * Get preferred mixer attributes that is previously set via
+ * {link #setPreferredMixerAttributes}.
+ */
+ public static native int getPreferredMixerAttributes(
+ @NonNull AudioAttributes attributes, int portId,
+ List<AudioMixerAttributes> mixerAttributesList);
+
+ /**
+ * @hide
+ * Clear preferred mixer attributes that is previously set via
+ * {@link #setPreferredMixerAttributes}
+ */
+ public static native int clearPreferredMixerAttributes(
+ @NonNull AudioAttributes attributes, int portId, int uid);
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ee453a4541c2..5502db2da4c6 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -23,6 +23,7 @@ import android.media.AudioDeviceAttributes;
import android.media.AudioFormat;
import android.media.AudioFocusInfo;
import android.media.AudioHalVersionInfo;
+import android.media.AudioMixerAttributes;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
@@ -37,6 +38,7 @@ import android.media.ICommunicationDeviceDispatcher;
import android.media.IDeviceVolumeBehaviorDispatcher;
import android.media.IMuteAwaitConnectionCallback;
import android.media.IPlaybackConfigDispatcher;
+import android.media.IPreferredMixerAttributesDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher;
@@ -573,4 +575,14 @@ interface IAudioService {
boolean handlesvolumeAdjustment);
AudioHalVersionInfo getHalVersion();
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)")
+ int setPreferredMixerAttributes(
+ in AudioAttributes aa, int portId, in AudioMixerAttributes mixerAttributes);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)")
+ int clearPreferredMixerAttributes(in AudioAttributes aa, int portId);
+ void registerPreferredMixerAttributesDispatcher(
+ IPreferredMixerAttributesDispatcher dispatcher);
+ oneway void unregisterPreferredMixerAttributesDispatcher(
+ IPreferredMixerAttributesDispatcher dispatcher);
}
diff --git a/services/permission/java/com/android/server/permission/access/external/PackageInfoUtils.kt b/media/java/android/media/IPreferredMixerAttributesDispatcher.aidl
index 24b28bd49fc9..9138fa74eccc 100644
--- a/services/permission/java/com/android/server/permission/access/external/PackageInfoUtils.kt
+++ b/media/java/android/media/IPreferredMixerAttributesDispatcher.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open 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,20 +14,21 @@
* limitations under the License.
*/
-package com.android.server.permission.access.external
+package android.media;
-import android.content.pm.PermissionGroupInfo
-import android.content.pm.PermissionInfo
+import android.media.AudioAttributes;
+import android.media.AudioMixerAttributes;
-object PackageInfoUtils {
- fun generatePermissionInfo(parsedPermission: ParsedPermission, flags: Long): PermissionInfo {
- throw NotImplementedError()
- }
+/**
+ * AIDL for AudioService to signal preferred mixer attributes update.
+ *
+ * {@hide}
+ */
+oneway interface IPreferredMixerAttributesDispatcher {
+
+ void dispatchPrefMixerAttributesChanged(
+ in AudioAttributes attributes,
+ int deviceId,
+ in @nullable AudioMixerAttributes mixerAttributes);
- fun generatePermissionGroupInfo(
- parsedPermissionGroup: ParsedPermissionGroup,
- flags: Long
- ): PermissionGroupInfo {
- throw NotImplementedError()
- }
}
diff --git a/media/java/android/media/MediaMetrics.java b/media/java/android/media/MediaMetrics.java
index a4a8cc44984f..5509782e2988 100644
--- a/media/java/android/media/MediaMetrics.java
+++ b/media/java/android/media/MediaMetrics.java
@@ -49,10 +49,11 @@ public class MediaMetrics {
public static final String AUDIO_FOCUS = AUDIO + SEPARATOR + "focus";
public static final String AUDIO_FORCE_USE = AUDIO + SEPARATOR + "forceUse";
public static final String AUDIO_MIC = AUDIO + SEPARATOR + "mic";
+ public static final String AUDIO_MIDI = AUDIO + SEPARATOR + "midi";
+ public static final String AUDIO_MODE = AUDIO + SEPARATOR + "mode";
public static final String AUDIO_SERVICE = AUDIO + SEPARATOR + "service";
public static final String AUDIO_VOLUME = AUDIO + SEPARATOR + "volume";
public static final String AUDIO_VOLUME_EVENT = AUDIO_VOLUME + SEPARATOR + "event";
- public static final String AUDIO_MODE = AUDIO + SEPARATOR + "mode";
public static final String METRICS_MANAGER = "metrics" + SEPARATOR + "manager";
}
@@ -90,15 +91,27 @@ public class MediaMetrics {
// The client name
public static final Key<String> CLIENT_NAME = createKey("clientName", String.class);
+ public static final Key<Integer> CLOSED_COUNT =
+ createKey("closedCount", Integer.class); // MIDI
+
// The device type
public static final Key<Integer> DELAY_MS = createKey("delayMs", Integer.class);
// The device type
public static final Key<String> DEVICE = createKey("device", String.class);
+ // Whether the device is disconnected. This is either "true" or "false"
+ public static final Key<String> DEVICE_DISCONNECTED =
+ createKey("deviceDisconnected", String.class); // MIDI
+
+ // The ID of the device
+ public static final Key<Integer> DEVICE_ID =
+ createKey("deviceId", Integer.class); // MIDI
+
// For volume changes, up or down
public static final Key<String> DIRECTION = createKey("direction", String.class);
-
+ public static final Key<Long> DURATION_NS =
+ createKey("durationNs", Long.class); // MIDI
// A reason for early return or error
public static final Key<String> EARLY_RETURN =
createKey("earlyReturn", String.class);
@@ -128,11 +141,17 @@ public class MediaMetrics {
// Generally string "true" or "false"
public static final Key<String> HAS_HEAD_TRACKER =
createKey("hasHeadTracker", String.class); // spatializer
+ public static final Key<Integer> HARDWARE_TYPE =
+ createKey("hardwareType", Integer.class); // MIDI
// Generally string "true" or "false"
public static final Key<String> HEAD_TRACKER_ENABLED =
createKey("headTrackerEnabled", String.class); // spatializer
public static final Key<Integer> INDEX = createKey("index", Integer.class); // volume
+ public static final Key<Integer> INPUT_PORT_COUNT =
+ createKey("inputPortCount", Integer.class); // MIDI
+ // Either "true" or "false"
+ public static final Key<String> IS_SHARED = createKey("isShared", String.class); // MIDI
public static final Key<String> LOG_SESSION_ID = createKey("logSessionId", String.class);
public static final Key<Integer> MAX_INDEX = createKey("maxIndex", Integer.class); // vol
public static final Key<Integer> MIN_INDEX = createKey("minIndex", Integer.class); // vol
@@ -149,6 +168,11 @@ public class MediaMetrics {
public static final Key<Integer> OBSERVERS =
createKey("observers", Integer.class);
+ public static final Key<Integer> OPENED_COUNT =
+ createKey("openedCount", Integer.class); // MIDI
+ public static final Key<Integer> OUTPUT_PORT_COUNT =
+ createKey("outputPortCount", Integer.class); // MIDI
+
public static final Key<String> REQUEST =
createKey("request", String.class);
@@ -163,6 +187,18 @@ public class MediaMetrics {
public static final Key<String> STATE = createKey("state", String.class);
public static final Key<Integer> STATUS = createKey("status", Integer.class);
public static final Key<String> STREAM_TYPE = createKey("streamType", String.class);
+
+ // The following MIDI string is generally either "true" or "false"
+ public static final Key<String> SUPPORTS_MIDI_UMP =
+ createKey("supportsMidiUmp", String.class); // Universal MIDI Packets
+
+ public static final Key<Integer> TOTAL_INPUT_BYTES =
+ createKey("totalInputBytes", Integer.class); // MIDI
+ public static final Key<Integer> TOTAL_OUTPUT_BYTES =
+ createKey("totalOutputBytes", Integer.class); // MIDI
+
+ // The following MIDI string is generally either "true" or "false"
+ public static final Key<String> USING_ALSA = createKey("usingAlsa", String.class);
}
/**
diff --git a/media/java/android/media/RouteListingPreference.java b/media/java/android/media/RouteListingPreference.java
index 62f233e42989..84e6d3c87461 100644
--- a/media/java/android/media/RouteListingPreference.java
+++ b/media/java/android/media/RouteListingPreference.java
@@ -142,7 +142,12 @@ public final class RouteListingPreference implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef(
prefix = {"DISABLE_REASON_"},
- value = {DISABLE_REASON_NONE, DISABLE_REASON_SUBSCRIPTION_REQUIRED})
+ value = {
+ DISABLE_REASON_NONE,
+ DISABLE_REASON_SUBSCRIPTION_REQUIRED,
+ DISABLE_REASON_DOWNLOADED_CONTENT,
+ DISABLE_REASON_AD
+ })
public @interface DisableReason {}
/** The corresponding route is available for routing. */
@@ -152,6 +157,13 @@ public final class RouteListingPreference implements Parcelable {
* routing.
*/
public static final int DISABLE_REASON_SUBSCRIPTION_REQUIRED = 1;
+ /**
+ * The corresponding route is not available because downloaded content cannot be routed to
+ * it.
+ */
+ public static final int DISABLE_REASON_DOWNLOADED_CONTENT = 2;
+ /** The corresponding route is not available because an ad is in progress. */
+ public static final int DISABLE_REASON_AD = 3;
@NonNull
public static final Creator<Item> CREATOR =
@@ -216,6 +228,8 @@ public final class RouteListingPreference implements Parcelable {
*
* @see #DISABLE_REASON_NONE
* @see #DISABLE_REASON_SUBSCRIPTION_REQUIRED
+ * @see #DISABLE_REASON_DOWNLOADED_CONTENT
+ * @see #DISABLE_REASON_AD
*/
@DisableReason
public int getDisableReason() {
diff --git a/media/java/android/media/midi/IMidiManager.aidl b/media/java/android/media/midi/IMidiManager.aidl
index b03f78504635..bd678a5e3197 100644
--- a/media/java/android/media/midi/IMidiManager.aidl
+++ b/media/java/android/media/midi/IMidiManager.aidl
@@ -60,4 +60,7 @@ interface IMidiManager
// used by MIDI devices to report their status
// the token is used by MidiService for death notification
void setDeviceStatus(in IMidiDeviceServer server, in MidiDeviceStatus status);
+
+ // Updates the number of bytes sent and received
+ void updateTotalBytes(in IMidiDeviceServer server, int inputBytes, int outputBytes);
}
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index d5916b9bd6ab..fc33cef9e733 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -36,6 +36,7 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Internal class used for providing an implementation for a MIDI device.
@@ -79,6 +80,9 @@ public final class MidiDeviceServer implements Closeable {
private final HashMap<MidiInputPort, PortClient> mInputPortClients =
new HashMap<MidiInputPort, PortClient>();
+ private AtomicInteger mTotalInputBytes = new AtomicInteger();
+ private AtomicInteger mTotalOutputBytes = new AtomicInteger();
+
public interface Callback {
/**
* Called to notify when an our device status has changed
@@ -133,6 +137,8 @@ public final class MidiDeviceServer implements Closeable {
int portNumber = mOutputPort.getPortNumber();
mInputPortOutputPorts[portNumber] = null;
mInputPortOpen[portNumber] = false;
+ mTotalOutputBytes.addAndGet(mOutputPort.pullTotalBytesCount());
+ updateTotalBytes();
updateDeviceStatus();
}
IoUtils.closeQuietly(mOutputPort);
@@ -156,6 +162,8 @@ public final class MidiDeviceServer implements Closeable {
dispatcher.getSender().disconnect(mInputPort);
int openCount = dispatcher.getReceiverCount();
mOutputPortOpenCount[portNumber] = openCount;
+ mTotalInputBytes.addAndGet(mInputPort.pullTotalBytesCount());
+ updateTotalBytes();
updateDeviceStatus();
}
@@ -405,18 +413,20 @@ public final class MidiDeviceServer implements Closeable {
synchronized (mGuard) {
if (mIsClosed) return;
mGuard.close();
-
for (int i = 0; i < mInputPortCount; i++) {
MidiOutputPort outputPort = mInputPortOutputPorts[i];
if (outputPort != null) {
+ mTotalOutputBytes.addAndGet(outputPort.pullTotalBytesCount());
IoUtils.closeQuietly(outputPort);
mInputPortOutputPorts[i] = null;
}
}
for (MidiInputPort inputPort : mInputPorts) {
+ mTotalInputBytes.addAndGet(inputPort.pullTotalBytesCount());
IoUtils.closeQuietly(inputPort);
}
mInputPorts.clear();
+ updateTotalBytes();
try {
mMidiManager.unregisterDeviceServer(mServer);
} catch (RemoteException e) {
@@ -449,4 +459,12 @@ public final class MidiDeviceServer implements Closeable {
System.arraycopy(mOutputPortDispatchers, 0, receivers, 0, mOutputPortCount);
return receivers;
}
+
+ private void updateTotalBytes() {
+ try {
+ mMidiManager.updateTotalBytes(mServer, mTotalInputBytes.get(), mTotalOutputBytes.get());
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in updateTotalBytes");
+ }
+ }
}
diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java
index a300886ea7c1..fe42b58bf315 100644
--- a/media/java/android/media/midi/MidiInputPort.java
+++ b/media/java/android/media/midi/MidiInputPort.java
@@ -28,6 +28,7 @@ import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* This class is used for sending data to a port on a MIDI device
@@ -43,6 +44,7 @@ public final class MidiInputPort extends MidiReceiver implements Closeable {
private final CloseGuard mGuard = CloseGuard.get();
private boolean mIsClosed;
+ private AtomicInteger mTotalBytes = new AtomicInteger();
// buffer to use for sending data out our output stream
private final byte[] mBuffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
@@ -87,6 +89,7 @@ public final class MidiInputPort extends MidiReceiver implements Closeable {
}
int length = MidiPortImpl.packData(msg, offset, count, timestamp, mBuffer);
mOutputStream.write(mBuffer, 0, length);
+ mTotalBytes.addAndGet(length);
}
}
@@ -170,4 +173,12 @@ public final class MidiInputPort extends MidiReceiver implements Closeable {
super.finalize();
}
}
+
+ /**
+ * Pulls total number of bytes and sets to zero. This allows multiple callers.
+ * @hide
+ */
+ public int pullTotalBytesCount() {
+ return mTotalBytes.getAndSet(0);
+ }
}
diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java
index 5411e669f14d..d9484779055d 100644
--- a/media/java/android/media/midi/MidiOutputPort.java
+++ b/media/java/android/media/midi/MidiOutputPort.java
@@ -31,6 +31,7 @@ import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* This class is used for receiving data from a port on a MIDI device
@@ -46,6 +47,7 @@ public final class MidiOutputPort extends MidiSender implements Closeable {
private final CloseGuard mGuard = CloseGuard.get();
private boolean mIsClosed;
+ private AtomicInteger mTotalBytes = new AtomicInteger();
// This thread reads MIDI events from a socket and distributes them to the list of
// MidiReceivers attached to this device.
@@ -83,6 +85,7 @@ public final class MidiOutputPort extends MidiSender implements Closeable {
Log.e(TAG, "Unknown packet type " + packetType);
break;
}
+ mTotalBytes.addAndGet(count);
} // while (true)
} catch (IOException e) {
// FIXME report I/O failure?
@@ -163,4 +166,12 @@ public final class MidiOutputPort extends MidiSender implements Closeable {
super.finalize();
}
}
+
+ /**
+ * Pulls total number of bytes and sets to zero. This allows multiple callers.
+ * @hide
+ */
+ public int pullTotalBytesCount() {
+ return mTotalBytes.getAndSet(0);
+ }
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index a2eae2c9579a..2b7bcbee79fd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -85,7 +85,8 @@ public class CameraBinderTest extends AndroidTestCase {
public void testCameraInfo() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
- CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId);
+ CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId,
+ /*overrideToPortrait*/false);
assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
assertTrue("Orientation was not set for camera " + cameraId,
info.info.orientation != -1);
@@ -159,7 +160,8 @@ public class CameraBinderTest extends AndroidTestCase {
.connect(dummyCallbacks, cameraId, clientPackageName,
ICameraService.USE_CALLING_UID,
ICameraService.USE_CALLING_PID,
- getContext().getApplicationInfo().targetSdkVersion);
+ getContext().getApplicationInfo().targetSdkVersion,
+ /*overrideToPortrait*/false);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -264,7 +266,8 @@ public class CameraBinderTest extends AndroidTestCase {
dummyCallbacks, String.valueOf(cameraId),
clientPackageName, clientAttributionTag,
ICameraService.USE_CALLING_UID, 0 /*oomScoreOffset*/,
- getContext().getApplicationInfo().targetSdkVersion);
+ getContext().getApplicationInfo().targetSdkVersion,
+ /*overrideToPortrait*/false);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 0890346db198..9d09dcc5c440 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -244,7 +244,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID,
- /*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion);
+ /*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion,
+ /*overrideToPortrait*/false);
assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
@@ -417,7 +418,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
@SmallTest
public void testCameraCharacteristics() throws RemoteException {
CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId,
- getContext().getApplicationInfo().targetSdkVersion);
+ getContext().getApplicationInfo().targetSdkVersion, /*overrideToPortrait*/false);
assertFalse(info.isEmpty());
assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
diff --git a/packages/CarrierDefaultApp/res/values-af/strings.xml b/packages/CarrierDefaultApp/res/values-af/strings.xml
index 3bc18ce1335e..f3ea488b8938 100644
--- a/packages/CarrierDefaultApp/res/values-af/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-af/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Die netwerk waarby jy probeer aansluit, het sekuriteitkwessies."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Byvoorbeeld, die aanmeldbladsy behoort dalk nie aan die organisasie wat gewys word nie."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Gaan in elk geval deur blaaier voort"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Netwerkhupstoot"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s beveel ’n datahupstoot aan"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Koop ’n netwerkhupstoot vir beter werkverrigting"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Nie nou nie"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Bestuur"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Koop ’n netwerkhupstoot."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ar/strings.xml b/packages/CarrierDefaultApp/res/values-ar/strings.xml
index cd979b2fd223..f5ae9f221e35 100644
--- a/packages/CarrierDefaultApp/res/values-ar/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ar/strings.xml
@@ -16,16 +16,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"الشبكة التي تحاول الانضمام إليها بها مشاكل أمنية."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"على سبيل المثال، قد لا تنتمي صفحة تسجيل الدخول إلى المؤسسة المعروضة."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"المتابعة على أي حال عبر المتصفح"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"خطة معزَّزة للشبكة"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"‏هناك اقتراح من %s بخطة معزَّزة للبيانات"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"من خلال شراء خطة معزَّزة للشبكة، يمكنك الاستفادة من أداء أفضل."</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"لاحقًا"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"إدارة"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"شراء خطة معزَّزة للشبكة"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-as/strings.xml b/packages/CarrierDefaultApp/res/values-as/strings.xml
index fdafe2b41bf8..b983fd1df1ff 100644
--- a/packages/CarrierDefaultApp/res/values-as/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-as/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"আপুনি সংযোগ কৰিবলৈ বিচৰা নেটৱৰ্কটোত সুৰক্ষাজনিত সমস্যা আছে।"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"উদাহৰণস্বৰূপে, আপোনাক দেখুওৱা লগ ইনৰ পৃষ্ঠাটো প্ৰতিষ্ঠানটোৰ নিজা নহ\'বও পাৰে।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"তথাপিও ব্ৰাউজাৰৰ জৰিয়তে অব্যাহত ৰাখক"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"নেটৱৰ্ক পৰিৱৰ্ধন"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%sএ এটা ডেটা পৰিৱৰ্ধনৰ চুপাৰিছ কৰিছে"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"উন্নত পাৰদৰ্শিতা পাবলৈ এটা নেটৱৰ্ক পৰিৱৰ্ধন ক্ৰয় কৰক"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"এতিয়া নহয়"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"পৰিচালনা কৰক"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"এটা নেটৱৰ্ক পৰিৱৰ্ধন ক্ৰয় কৰক।"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-az/strings.xml b/packages/CarrierDefaultApp/res/values-az/strings.xml
index 32c3c1ce2b95..3e6e1a80b13c 100644
--- a/packages/CarrierDefaultApp/res/values-az/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-az/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Qoşulmaq istədiyiniz şəbəkənin təhlükəsizlik problemləri var."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Məsələn, giriş səhifəsi göstərilən təşkilata aid olmaya bilər."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Hər bir halda brazuer ilə davam edin"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Əlavə trafik"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s əlavə data trafiki almağı tövsiyə edir"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Daha yaxşı performans üçün əlavə şəbəkə trafiki alın"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"İndi yox"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"İdarə edin"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Əlavə trafik alın."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
index 932fc03a3178..a1974f0da1aa 100644
--- a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj pokušavate da se pridružite ima bezbednosnih problema."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Na primer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko pregledača"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Pojačanje mreže"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s preporučuje povećanje podataka"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Kupite pojačanje mreže za bolji učinak"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ne sada"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Upravljajte"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Kupite pojačanje mreže."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-be/strings.xml b/packages/CarrierDefaultApp/res/values-be/strings.xml
index 20606f6bd71a..1cb013b5b24f 100644
--- a/packages/CarrierDefaultApp/res/values-be/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-be/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"У сеткі, да якой вы спрабуеце далучыцца, ёсць праблемы з бяспекай."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Напрыклад, старонка ўваходу можа не належаць указанай арганізацыі."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Усё роўна працягнуць праз браўзер"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Паскарэнне сеткі"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s рэкамендуе паскарэнне перадачы даных"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Купіце паскарэнне сеткі, каб павысіць прадукцыйнасць"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Не цяпер"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Кіраваць"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Купіць паскарэнне сеткі."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-bg/strings.xml b/packages/CarrierDefaultApp/res/values-bg/strings.xml
index 46a9db519af4..aee67d73cb9a 100644
--- a/packages/CarrierDefaultApp/res/values-bg/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bg/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Мрежата, към която опитвате да се присъедините, има проблеми със сигурността."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Например страницата за вход може да не принадлежи на показаната организация."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Продължаване през браузър въпреки това"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Подсилване на мрежата"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s препоръчва увеличаване на данните"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Купете подсилване на мрежата за по-висока ефективност"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Не сега"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Управление"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Купете подсилване на мрежата."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-bn/strings.xml b/packages/CarrierDefaultApp/res/values-bn/strings.xml
index 0826ae1dc14f..7f93175961c3 100644
--- a/packages/CarrierDefaultApp/res/values-bn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bn/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন সেটিতে নিরাপত্তাজনিত সমস্যা আছে।"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"যেমন, লগ-ইন পৃষ্ঠাটি যে প্রতিষ্ঠানের পৃষ্ঠা বলে দেখানো আছে, আসলে তা নাও হতে পারে৷"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"যাই হোক, ব্রাউজারের মাধ্যমে চালিয়ে যান"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"নেটওয়ার্ক বুস্ট"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ডেটা বুস্ট করার জন্য সাজেস্ট করে"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"আরও ভাল পারফর্ম্যান্সের জন্য নেটওয়ার্ক বুস্ট কিনুন"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"এখন নয়"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"ম্যানেজ করুন"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"নেটওয়ার্ক বুস্ট কিনুন।"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml
index e2bc342a41b5..093f03fc4502 100644
--- a/packages/CarrierDefaultApp/res/values-bs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj pokušavate pristupiti ima sigurnosnih problema."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Naprimjer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko preglednika"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Pojačanje mreže"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s preporučuje povećanje podataka"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Kupite pojačanje mreže za bolju izvedbu"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ne sad"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Upravljajte"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Kupite pojačanje mreže."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ca/strings.xml b/packages/CarrierDefaultApp/res/values-ca/strings.xml
index bdde56704f9a..63b243ac4a75 100644
--- a/packages/CarrierDefaultApp/res/values-ca/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ca/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"La xarxa a què et vols connectar té problemes de seguretat."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Per exemple, la pàgina d\'inici de sessió podria no pertànyer a l\'organització que es mostra."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continua igualment mitjançant el navegador"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Optimització de xarxa"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomana optimitzar les dades"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Compra una optimització de xarxa per millorar-ne el rendiment"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ara no"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gestiona"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Compra una optimització de xarxa."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-cs/strings.xml b/packages/CarrierDefaultApp/res/values-cs/strings.xml
index d5fdac963112..3cff883631c3 100644
--- a/packages/CarrierDefaultApp/res/values-cs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-cs/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Síť, ke které se pokoušíte připojit, má bezpečnostní problémy."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Přihlašovací stránka například nemusí patřit zobrazované organizaci."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Přesto pokračovat prostřednictvím prohlížeče"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Zesilovač sítě"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s doporučuje zesílení datového připojení"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Pořiďte si zesilovač, který zvýší výkon sítě"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Teď ne"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Spravovat"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Kupte si zesilovač sítě."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-da/strings.xml b/packages/CarrierDefaultApp/res/values-da/strings.xml
index 8b2bb7c164e2..487f62caf001 100644
--- a/packages/CarrierDefaultApp/res/values-da/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-da/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Der er sikkerhedsproblemer på det netværk, du forsøger at logge ind på."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Det er f.eks. ikke sikkert, at loginsiden tilhører den anførte organisation."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Fortsæt alligevel via browseren"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Netværksboost"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s anbefaler et databoost"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Køb et netværksboost for at få en bedre ydeevne"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ikke nu"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Administrer"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Køb et netværksboost."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-de/strings.xml b/packages/CarrierDefaultApp/res/values-de/strings.xml
index 21af41cc5a59..1394d107ef55 100644
--- a/packages/CarrierDefaultApp/res/values-de/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-de/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Trotzdem in einem Browser fortfahren"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Netzwerk-Boost"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s empfiehlt einen Daten-Boost"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Netzwerk-Boost für bessere Leistung kaufen"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Nicht jetzt"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Verwalten"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Jetzt Netzwerk-Boost kaufen."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-el/strings.xml b/packages/CarrierDefaultApp/res/values-el/strings.xml
index 75143143d497..3551401996fa 100644
--- a/packages/CarrierDefaultApp/res/values-el/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-el/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Παρουσιάζονται προβλήματα ασφάλειας στο δίκτυο στο οποίο προσπαθείτε να συνδεθείτε."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Για παράδειγμα, η σελίδα σύνδεσης ενδέχεται να μην ανήκει στον οργανισμό που εμφανίζεται."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Συνέχεια ούτως ή άλλως μέσω του προγράμματος περιήγησης"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Ενίσχυση δικτύου"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"Η %s συνιστά ενίσχυση δεδομένων"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Αγοράστε ενίσχυση δικτύου για καλύτερη απόδοση"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Όχι τώρα"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Διαχείριση"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Αγορά ενίσχυσης δικτύου."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
index bddae48eb2d0..5fa83471816d 100644
--- a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"La red a la que intentas conectarte tiene problemas de seguridad."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de acceso no pertenezca a la organización que aparece."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos desde el navegador"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Potenciación de red"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomienda un potenciador de datos"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Compra un potenciador de red para obtener un mejor rendimiento"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ahora no"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Administrar"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Compra un potenciador de red."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-es/strings.xml b/packages/CarrierDefaultApp/res/values-es/strings.xml
index dd56770857e3..e65bc9b06589 100644
--- a/packages/CarrierDefaultApp/res/values-es/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-es/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"La red a la que intentas unirte tiene problemas de seguridad."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de inicio de sesión no pertenezca a la organización mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos a través del navegador"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Mejora de red"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomienda una mejora de datos"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Compra una mejora de red para impulsar el rendimiento"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ahora no"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gestionar"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Compra una mejora de red."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-et/strings.xml b/packages/CarrierDefaultApp/res/values-et/strings.xml
index 8cdc2919e027..a951e7fee145 100644
--- a/packages/CarrierDefaultApp/res/values-et/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-et/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Võrgul, millega üritate ühenduse luua, on turvaprobleeme."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Näiteks ei pruugi sisselogimisleht kuuluda kuvatavale organisatsioonile."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Jätka siiski brauseris"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Võrgu võimendus"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s soovitab andmeside võimendust"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Ostke võrgu võimendus, et toimivust parandada"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Mitte praegu"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Haldamine"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Ostke võrgu võimendus."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-eu/strings.xml b/packages/CarrierDefaultApp/res/values-eu/strings.xml
index 22565dca4cf6..ad80cc91ae61 100644
--- a/packages/CarrierDefaultApp/res/values-eu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-eu/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Erabili nahi duzun sareak segurtasun-arazoak ditu."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Adibidez, baliteke saioa hasteko orria adierazitako erakundearena ez izatea."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Jarraitu arakatzailearen bidez, halere"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Sarearen hobekuntza"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s zerbitzuak datuak hobetzeko gomendatzen du"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Errendimendua areagotzeko, erosi sarearen hobekuntza bat"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Orain ez"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Kudeatu"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Erosi sarearen hobekuntza bat."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fa/strings.xml b/packages/CarrierDefaultApp/res/values-fa/strings.xml
index ecb9930be98a..4f55d7678fe5 100644
--- a/packages/CarrierDefaultApp/res/values-fa/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fa/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"شبکه‌ای که می‌خواهید به آن بپیوندید مشکلات امنیتی دارد."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"به عنوان مثال، صفحه ورود به سیستم ممکن است متعلق به سازمان نشان داده شده نباشد."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"درهر صورت ازطریق مرورگر ادامه یابد"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"تقویت‌کننده شبکه"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"‏%s توصیه می‌کند از تقویت‌کننده داده استفاده کنید"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"برای بهبود عملکرد، تقویت‌کننده شبکه خریداری کنید"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"اکنون نه"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"مدیریت"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"تقویت‌کننده شبکه بخرید."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fi/strings.xml b/packages/CarrierDefaultApp/res/values-fi/strings.xml
index 850f9db2a438..5ceddfb71f11 100644
--- a/packages/CarrierDefaultApp/res/values-fi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fi/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Verkossa, johon yrität muodostaa yhteyttä, havaittiin turvallisuusongelmia."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Kirjautumissivu ei välttämättä kuulu näytetylle organisaatiolle."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Jatka selaimen kautta"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Tehokkaampi verkko"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s suosittelee tehokkaampaa verkkoa"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Osta tehokkaampi verkko, jotta saat parempia tuloksia"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ei nyt"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Muokkaa"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Osta tehokkaampi verkko."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
index 61fc2e4e1780..d7dc3ac2e03b 100644
--- a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Le réseau que vous essayez de joindre présente des problèmes de sécurité."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion pourrait ne pas appartenir à l\'organisation représentée."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans un navigateur"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Amplification de réseau"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recommande une augmentation des données"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Acheter une amplification de réseau pour de meilleures performances"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Plus tard"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gérer"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Acheter une amplification de réseau."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-fr/strings.xml b/packages/CarrierDefaultApp/res/values-fr/strings.xml
index ef1857d925d0..2067e7bd2577 100644
--- a/packages/CarrierDefaultApp/res/values-fr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fr/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Le réseau auquel vous essayez de vous connecter présente des problèmes de sécurité."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion peut ne pas appartenir à l\'organisation représentée."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans le navigateur"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Boost réseau"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recommande de booster les données"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Achetez un boost réseau pour améliorer les performances"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Pas maintenant"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gérer"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Acheter un boost réseau."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-gl/strings.xml b/packages/CarrierDefaultApp/res/values-gl/strings.xml
index 6dde8a87d3ea..a01941f471f6 100644
--- a/packages/CarrierDefaultApp/res/values-gl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-gl/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"A rede á que tentas unirte ten problemas de seguranza."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, é posible que a páxina de inicio de sesión non pertenza á organización que se mostra."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar igualmente co navegador"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Optimizador de rede"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomenda un optimizador de datos"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Compra un optimizador de rede para obter un mellor rendemento"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Agora non"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Xestionar"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Compra un optimizador de rede."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-gu/strings.xml b/packages/CarrierDefaultApp/res/values-gu/strings.xml
index 473a0357f9af..28f9ecb84395 100644
--- a/packages/CarrierDefaultApp/res/values-gu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-gu/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"તમે જોડાવાનો પ્રયાસ કરી રહ્યા છો તે નેટવર્કમાં સુરક્ષા સંબંધી સમસ્યાઓ છે."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ઉદાહરણ તરીકે, લોગિન પૃષ્ઠ બતાવવામાં આવેલી સંસ્થાનું ન પણ હોય."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"તો પણ બ્રાઉઝર મારફતે ચાલુ રાખો"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"નેટવર્ક બૂસ્ટ"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"ડેટા બૂસ્ટનો સુઝાવ %s દ્વારા આપવામાં આવે છે"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"બહેતર પર્ફોર્મન્સ માટે, કોઈ નેટવર્ક બૂસ્ટ ખરીદો"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"હમણાં નહીં"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"મેનેજ કરો"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"કોઈ નેટવર્ક બૂસ્ટ ખરીદો."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hi/strings.xml b/packages/CarrierDefaultApp/res/values-hi/strings.xml
index d878c1c55996..75206b78efd1 100644
--- a/packages/CarrierDefaultApp/res/values-hi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hi/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"आप जिस नेटवर्क में शामिल होने की कोशिश कर रहे हैं उसमें सुरक्षा से जुड़ी समस्‍याएं हैं."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरण के लिए, हो सकता है कि लॉगिन पेज दिखाए गए संगठन का ना हो."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ब्राउज़र के ज़रिए किसी भी तरह जारी रखें"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"नेटवर्क बूस्ट"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s, डेटा बूस्ट इस्तेमाल करने का सुझाव देता है"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"बेहतर परफ़ॉर्मेंस के लिए, नेटवर्क बूस्ट खरीदें"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"अभी नहीं"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"मैनेज करें"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"नेटवर्क बूस्ट खरीदें."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hr/strings.xml b/packages/CarrierDefaultApp/res/values-hr/strings.xml
index 0da2280ba1a3..d31f4f8bacbd 100644
--- a/packages/CarrierDefaultApp/res/values-hr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hr/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj se pokušavate pridružiti ima sigurnosne poteškoće."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Na primjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi putem preglednika"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Pojačanje mreže"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s preporučuje povećanje podataka"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Kupite pojačanje mreže za bolju izvedbu"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ne sad"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Upravljajte"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Kupite pojačanje mreže."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml
index 95c1db86fc23..afd67422d38e 100644
--- a/packages/CarrierDefaultApp/res/values-hu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Például lehetséges, hogy a bejelentkezési oldal nem a megjelenített szervezethez tartozik."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Folytatás ennek ellenére böngészőn keresztül"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Teljesítménynövelés"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s a teljesítménynövelést javasol"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Vásároljon teljesítménynövelési lehetőséget a jobb teljesítmény érdekében"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Most nem"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Kezelés"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Vásároljon teljesítménynövelést."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hy/strings.xml b/packages/CarrierDefaultApp/res/values-hy/strings.xml
index a846e044e7a4..1effc3db80f7 100644
--- a/packages/CarrierDefaultApp/res/values-hy/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hy/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Ցանցը, որին փորձում եք միանալ, անվտանգության խնդիրներ ունի:"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Օրինակ՝ մուտքի էջը կարող է ցուցադրված կազմակերպության էջը չլինել:"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Շարունակել դիտարկիչի միջոցով"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Բջջային ինտերնետի փաթեթ"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s-ը խորհուրդ է տալիս գնել բջջային ինտերնետի փաթեթ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Գնեք բջջային ինտերնետի փաթեթ՝ աշխատանքի արդյունավետությունը լավացնելու համար"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ոչ հիմա"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Կառավարել"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Գնել ցանցի բջջային ինտերնետի փաթեթ։"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-in/strings.xml b/packages/CarrierDefaultApp/res/values-in/strings.xml
index 488ad09a0d32..ed7385ad9309 100644
--- a/packages/CarrierDefaultApp/res/values-in/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-in/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Jaringan yang ingin Anda masuki memiliki masalah keamanan."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Misalnya, halaman login mungkin bukan milik organisasi yang ditampilkan."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Tetap lanjutkan melalui browser"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Penguat sinyal"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s merekomendasikan penguat sinyal data seluler"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Beli penguat sinyal untuk performa yang lebih baik"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Lain kali"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Kelola"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Beli penguat sinyal."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-is/strings.xml b/packages/CarrierDefaultApp/res/values-is/strings.xml
index ab4981d19579..df8c01b49d8a 100644
--- a/packages/CarrierDefaultApp/res/values-is/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-is/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Öryggisvandamál eru á netinu sem þú ert að reyna að tengjast."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Til dæmis getur verið að innskráningarsíðan tilheyri ekki fyrirtækinu sem birtist."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Halda samt áfram í vafra"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Nethröðun"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s mælir með auknu gagnamagni"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Kauptu nethröðun til að bæta afköstin"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ekki núna"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Stjórna"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Kaupa nethröðun."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-it/strings.xml b/packages/CarrierDefaultApp/res/values-it/strings.xml
index 95ea06084240..3c76f21175aa 100644
--- a/packages/CarrierDefaultApp/res/values-it/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-it/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"La rete a cui stai tentando di accedere presenta problemi di sicurezza."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Ad esempio, la pagina di accesso potrebbe non appartenere all\'organizzazione indicata."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continua comunque dal browser"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Potenziamento di rete"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s consiglia un aumento dei dati"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Acquista un potenziamento di rete per migliorare le prestazioni"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Non ora"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gestisci"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Acquista un potenziamento di rete."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-iw/strings.xml b/packages/CarrierDefaultApp/res/values-iw/strings.xml
index 263ed1ab4c3e..9f7cc8e72a1e 100644
--- a/packages/CarrierDefaultApp/res/values-iw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-iw/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"יש בעיות אבטחה ברשת שאליה אתה מנסה להתחבר."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"לדוגמה, ייתכן שדף ההתחברות אינו שייך לארגון המוצג."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"המשך בכל זאת באמצעות דפדפן"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"מגבר לרשת"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"‏יש המלצה של %s להגברת הרשת"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"קניית מגבר לרשת לשיפור הביצועים"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"לא עכשיו"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"ניהול"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"קניית מגבר לרשת."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ja/strings.xml b/packages/CarrierDefaultApp/res/values-ja/strings.xml
index 3b22ae186196..4b709afc8f6f 100644
--- a/packages/CarrierDefaultApp/res/values-ja/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ja/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"接続しようとしているネットワークにセキュリティの問題があります。"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"たとえば、ログインページが表示されている組織に属していない可能性があります。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ブラウザから続行"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ネットワーク ブースト"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ではデータブーストが推奨されます"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"ネットワーク ブーストを購入してパフォーマンスを改善しましょう"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"後で"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"管理"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ネットワーク ブーストを購入できます。"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ka/strings.xml b/packages/CarrierDefaultApp/res/values-ka/strings.xml
index 4b9cd387f0a1..713c48831dfa 100644
--- a/packages/CarrierDefaultApp/res/values-ka/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ka/strings.xml
@@ -14,16 +14,12 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"ქსელს, რომელთან დაკავშრებასაც ცდილობთ, უსაფრთხოების პრობლემები აქვს."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"მაგალითად, სისტემაში შესვლის გვერდი შეიძლება არ ეკუთვნოდეს ნაჩვენებ ორგანიზაციას."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"მაინც ბრაუზერში გაგრძელება"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ქსელის გაძლიერება"</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for network_boost_notification_title (8226368121348880044) -->
<skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"შეიძინეთ ქსელის გაძლიერება უკეთესი მუშაობისთვის"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ახლა არა"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"მართვა"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"შეიძინეთ ქსელის გაძლიერება."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-kk/strings.xml b/packages/CarrierDefaultApp/res/values-kk/strings.xml
index fce8dd24a036..13fdc0a1e4b7 100644
--- a/packages/CarrierDefaultApp/res/values-kk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-kk/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Қосылайын деп жатқан желіңізде қауіпсіздік мәселелері бар."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Мысалы, кіру беті көрсетілген ұйымға тиесілі болмауы мүмкін."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Бәрібір браузер арқылы жалғастыру"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Күшейтілген желі"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s күшейтілген желі пакетін ұсынады"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Өнімділікті арттыру үшін күшейтілген желі пакетін сатып алыңыз."</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Қазір емес"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Басқару"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Күшейтілген желіні сатып алыңыз."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-km/strings.xml b/packages/CarrierDefaultApp/res/values-km/strings.xml
index 983f09e74111..7993f6fd4552 100644
--- a/packages/CarrierDefaultApp/res/values-km/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-km/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"បណ្តាញដែលអ្នកកំពុងព្យាយាមចូលមានបញ្ហាសុវត្ថិភាព។"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ឧទាហរណ៍៖ ទំព័រចូលនេះអាចនឹងមិនមែនជាកម្មសិទ្ធិរបស់ស្ថាប័នដែលបានបង្ហាញនេះទេ។"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"យ៉ាងណាក៏ដោយនៅតែបន្តតាមរយៈកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ការបង្កើនល្បឿនបណ្ដាញ"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ណែនាំ​ឱ្យបង្កើន​ទិន្នន័យ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"ទិញ​ការបង្កើនល្បឿនបណ្ដាញ ដើម្បីឱ្យប្រតិបត្តិការ​ប្រសើរជាងមុន"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"កុំទាន់"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"គ្រប់គ្រង"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ទិញការបង្កើន​ល្បឿនបណ្ដាញ។"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-kn/strings.xml b/packages/CarrierDefaultApp/res/values-kn/strings.xml
index 86b29cece868..323885e1a431 100644
--- a/packages/CarrierDefaultApp/res/values-kn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-kn/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"ನೀವು ಸೇರಬೇಕೆಂದಿರುವ ನೆಟ್‌ವರ್ಕ್, ಭದ್ರತೆ ಸಮಸ್ಯೆಗಳನ್ನು ಹೊಂದಿದೆ."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ಉದಾಹರಣೆಗೆ, ಲಾಗಿನ್ ಪುಟವು ತೋರಿಸಲಾಗಿರುವ ಸಂಸ್ಥೆಗೆ ಸಂಬಂಧಿಸಿಲ್ಲದಿರಬಹುದು."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ಪರವಾಗಿಲ್ಲ, ಬ್ರೌಸರ್ ಮೂಲಕ ಮುಂದುವರಿಸಿ"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ನೆಟ್‌ವರ್ಕ್ ಬೂಸ್ಟ್"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ಡೇಟಾ ಬೂಸ್ಟ್ ಅನ್ನು ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"ಉತ್ತಮ ಕಾರ್ಯಕ್ಷಮತೆಗಾಗಿ ನೆಟ್‌ವರ್ಕ್ ಬೂಸ್ಟ್ ಅನ್ನು ಖರೀದಿಸಿ"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ಸದ್ಯಕ್ಕೆ ಬೇಡ"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"ನಿರ್ವಹಿಸಿ"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ನೆಟ್‌ವರ್ಕ್ ಬೂಸ್ಟ್ ಖರೀದಿಸಿ."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ko/strings.xml b/packages/CarrierDefaultApp/res/values-ko/strings.xml
index 3c6f4a67228f..8ce69a33a45f 100644
--- a/packages/CarrierDefaultApp/res/values-ko/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ko/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"가입하려는 네트워크에 보안 문제가 있습니다."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"예를 들어 로그인 페이지가 표시된 조직에 속하지 않을 수 있습니다."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"브라우저를 통해 계속하기"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"성능 향상"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s에서 성능 향상을 권장합니다"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"성능 향상을 구매하여 성능을 개선하세요."</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"나중에"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"관리"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"성능 향상을 구매하세요."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml
index 3cece7de3a18..637620c22dd4 100644
--- a/packages/CarrierDefaultApp/res/values-ky/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Кошулайын деген тармагыңызда коопсуздук көйгөйлөрү бар."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Мисалы, аккаунтка кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Баары бир серепчи аркылуу улантуу"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Тармакты оптималдаштыруу"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s тармак оптималдаштыруусун сунуштайт"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Иштин майнаптуулугун жогорулатуу үчүн тармакты оптималдаштыруу мүмкүнчүлүгүн сатып алыңыз"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Азыр эмес"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Тескөө"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Тармакты оптималдаштырууну сатып алыңыз."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-lo/strings.xml b/packages/CarrierDefaultApp/res/values-lo/strings.xml
index c6c0533b09e1..124e5cc79c5e 100644
--- a/packages/CarrierDefaultApp/res/values-lo/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lo/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"ເຄືອຂ່າຍທີ່ທ່ານກຳລັງເຂົ້າຮ່ວມມີບັນຫາຄວາມປອດໄພ."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ຕົວຢ່າງ, ໜ້າເຂົ້າສູ່ລະບົບອາດຈະບໍ່ແມ່ນຂອງອົງກອນທີ່ປາກົດ."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ດຳເນີນການຕໍ່ຜ່ານໂປຣແກຣມທ່ອງເວັບ"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ການເພີ່ມປະສິດທິພາບເຄືອຂ່າຍ"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ແນະນຳໃຫ້ເພີ່ມປະສິດທິພາບຂໍ້ມູນ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"ຊື້ການເພີ່ມປະສິດທິພາບເຄືອຂ່າຍເພື່ອປະສິດທິພາບການເຮັດວຽກທີ່ດີຂຶ້ນ"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ບໍ່ຟ້າວເທື່ອ"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"ຈັດການ"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ຊື້ການເພີ່ມປະສິດທິພາບເຄືອຂ່າຍ."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-lt/strings.xml b/packages/CarrierDefaultApp/res/values-lt/strings.xml
index fe33b1de6c75..61e159325cb3 100644
--- a/packages/CarrierDefaultApp/res/values-lt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lt/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Kilo tinklo, prie kurio bandote prisijungti, saugos problemų."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Pavyzdžiui, prisijungimo puslapis gali nepriklausyti rodomai organizacijai."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vis tiek tęsti naudojant naršyklę"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Papildomi duomenys"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s rekomenduoja įsigyti papildomų duomenų"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Įsigykite papildomų duomenų, kad pagerintumėte našumą"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ne dabar"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Tvarkyti"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Įsigykite papildomų duomenų."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-lv/strings.xml b/packages/CarrierDefaultApp/res/values-lv/strings.xml
index f8864e2a0e52..3472b4c4050f 100644
--- a/packages/CarrierDefaultApp/res/values-lv/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lv/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Tīklā, kuram mēģināt pievienoties, ir drošības problēmas."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Piemēram, pieteikšanās lapa, iespējams, nepieder norādītajai organizācijai."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Tomēr turpināt, izmantojot pārlūkprogrammu"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Tīkla veiktspējas uzlabojums"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s iesaka veiktspējas uzlabojumu"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Iegādājieties tīkla veiktspējas uzlabojumu."</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Vēlāk"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Pārvaldīt"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Iegādājieties tīkla veiktspējas uzlabojumu."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-mk/strings.xml b/packages/CarrierDefaultApp/res/values-mk/strings.xml
index 0b8daafe8d41..759c58adc3b4 100644
--- a/packages/CarrierDefaultApp/res/values-mk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mk/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Мрежата на која се обидувате да се придружите има проблеми со безбедноста."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"На пример, страницата за најавување може да не припаѓа на прикажаната организација."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Сепак продолжи преку прелистувач"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Засилување за мрежата"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s препорачува засилување за мрежата"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Купете засилување за мрежата за подобра изведба"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Не сега"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Управувајте"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Купете засилување за мрежата."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ml/strings.xml b/packages/CarrierDefaultApp/res/values-ml/strings.xml
index f27d4d864a3b..08a04e374a7f 100644
--- a/packages/CarrierDefaultApp/res/values-ml/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ml/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"നിങ്ങൾ ചേരാൻ ശ്രമിക്കുന്ന നെറ്റ്‌വർക്കിൽ സുരക്ഷാ പ്രശ്‌നങ്ങളുണ്ടായിരിക്കാം."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ഉദാഹരണത്തിന്, കാണിച്ചിരിക്കുന്ന ഓർഗനൈസേഷന്റേതായിരിക്കില്ല ലോഗിൻ പേജ്."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"എന്തായാലും ബ്രൗസർ വഴി തുടരുക"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"നെറ്റ്‌വർക്ക് ബൂസ്റ്റ്"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ഡാറ്റാ ബൂസ്റ്റ് നിർദ്ദേശിക്കുന്നു"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"മികച്ച പ്രകടനത്തിന് നെറ്റ്‌വർക്ക് ബൂസ്റ്റ് വാങ്ങുക"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ഇപ്പോൾ വേണ്ട"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"മാനേജ് ചെയ്യുക"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ഒരു നെറ്റ്‌വർക്ക് ബൂസ്‌റ്റ് വാങ്ങുക."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-mn/strings.xml b/packages/CarrierDefaultApp/res/values-mn/strings.xml
index 354bd349ac41..5ef4243a1254 100644
--- a/packages/CarrierDefaultApp/res/values-mn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mn/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Таны холбогдох гэж буй сүлжээ аюулгүй байдлын асуудалтай байна."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Жишээлбэл нэвтрэх хуудас нь харагдаж буй байгууллагынх биш байж болно."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ямар ч тохиолдолд хөтчөөр үргэлжлүүлэх"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Сүлжээний идэвхжүүлэлт"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s дата идэвхжүүлэлтийг санал болгодог"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Илүү сайн гүйцэтгэл авах бол сүлжээний идэвхжүүлэлтийг худалдаж авна уу"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Одоо биш"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Удирдах"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Сүлжээний идэвхжүүлэлтийг худалдан авна уу."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-mr/strings.xml b/packages/CarrierDefaultApp/res/values-mr/strings.xml
index c61d3c8e2eea..930ed8cdbfdc 100644
--- a/packages/CarrierDefaultApp/res/values-mr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mr/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"तुम्ही ज्या नेटवर्कमध्‍ये सामील होण्याचा प्रयत्न करत आहात त्यात सुरक्षितता समस्या आहेत."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणार्थ, लॉग इन पृष्‍ठ दर्शवलेल्या संस्थेच्या मालकीचे नसू शकते."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"तरीही ब्राउझरद्वारे सुरू ठेवा"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"नेटवर्क बूस्ट"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s डेटा बूस्टची शिफारस करते"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"आणखी चांगल्या परफॉर्मन्ससाठी नेटवर्क बूस्ट खरेदी करा"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"आता नको"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"व्यवस्थापित करा"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"नेटवर्क बूस्ट खरेदी करा."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ms/strings.xml b/packages/CarrierDefaultApp/res/values-ms/strings.xml
index 366463ff90ce..2f959154c88a 100644
--- a/packages/CarrierDefaultApp/res/values-ms/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ms/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Rangkaian yang cuba anda sertai mempunyai isu keselamatan."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Contohnya, halaman log masuk mungkin bukan milik organisasi yang ditunjukkan."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Teruskan juga melalui penyemak imbas"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Perangsang rangkaian"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s mengesyorkan peningkatan data"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Beli perangsang rangkaian untuk mendapatkan prestasi yang lebih baik"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Bukan sekarang"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Urus"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Beli perangsang rangkaian."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-my/strings.xml b/packages/CarrierDefaultApp/res/values-my/strings.xml
index 2fa618829f51..1ca4317970f5 100644
--- a/packages/CarrierDefaultApp/res/values-my/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-my/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"သင်ချိတ်ဆက်ရန် ကြိုးစားနေသည့် ကွန်ရက်တွင် လုံခြုံရေးပြဿနာများ ရှိနေသည်။"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ဥပမာ− ဝင်ရောက်ရန် စာမျက်နှာသည် ပြသထားသည့် အဖွဲ့အစည်းနှင့် သက်ဆိုင်မှုမရှိခြင်း ဖြစ်နိုင်ပါသည်။"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"မည်သို့ပင်ဖြစ်စေ ဘရောက်ဇာမှတစ်ဆင့် ရှေ့ဆက်ရန်"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ကွန်ရက်မြှင့်တင်အက်ပ်"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s က ဒေတာမြှင့်တင်ရန် အကြံပြုသည်"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"စွမ်းဆောင်ရည် ပိုကောင်းစေရန် ကွန်ရက်မြှင့်တင်အက်ပ် ဝယ်ပါ"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ယခုမလုပ်ပါ"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"စီမံရန်"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ကွန်ရက်မြှင့်တင်အက်ပ် ဝယ်ယူရန်။"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-nb/strings.xml b/packages/CarrierDefaultApp/res/values-nb/strings.xml
index 16f8eaadcb0a..86602072604c 100644
--- a/packages/CarrierDefaultApp/res/values-nb/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-nb/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Nettverket du prøver å logge på, har sikkerhetsproblemer."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Det er for eksempel mulig at påloggingssiden ikke tilhører organisasjonen som vises."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Fortsett likevel via nettleseren"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Nettverksboost"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s anbefaler en databoost"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Kjøp en nettverksboost for å få bedre ytelse"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ikke nå"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Administrer"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Kjøp en nettverksboost."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ne/strings.xml b/packages/CarrierDefaultApp/res/values-ne/strings.xml
index cb175df24a12..c92237cb4136 100644
--- a/packages/CarrierDefaultApp/res/values-ne/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ne/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"तपाईंले सामेल हुने प्रयास गरिरहनु भएको नेटवर्कमा सुरक्षा सम्बन्धी समस्याहरू छन्।"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणका लागि, लग इन पृष्ठ देखाइएको संस्थाको नहुन सक्छ।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"जे भए पनि ब्राउजर मार्फत जारी राख्नुहोस्"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"नेटवर्क बुस्ट"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ले डेटा बुस्ट किन्न सिफारिस गर्छ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"अझ राम्रो पर्फर्मेन्सका लागि नेटवर्क बुस्ट किन्नुहोस्"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"अहिले होइन"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"व्यवस्थापन गर्नुहोस्"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"नेटवर्क बुस्ट किन्नुहोस्।"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-nl/strings.xml b/packages/CarrierDefaultApp/res/values-nl/strings.xml
index 8511ff5e9ab3..1cd929ee23bd 100644
--- a/packages/CarrierDefaultApp/res/values-nl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-nl/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Het netwerk waarmee je verbinding probeert te maken, heeft beveiligingsproblemen."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Zo hoort de weergegeven inlogpagina misschien niet bij de weergegeven organisatie."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Toch doorgaan via browser"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Netwerkboost"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s raadt een databoost aan"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Koop een netwerkboost voor betere prestaties"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Niet nu"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Beheren"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Koop een netwerkboost."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-or/strings.xml b/packages/CarrierDefaultApp/res/values-or/strings.xml
index 65fd7bb687b5..4a01c1278fad 100644
--- a/packages/CarrierDefaultApp/res/values-or/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-or/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"ଆପଣ ଯୋଗ ଦେବାକୁ ଚେଷ୍ଟା କରୁଥିବା ନେଟୱର୍କର ସୁରକ୍ଷା ସମସ୍ୟା ଅଛି।"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ଉଦାହରଣସ୍ୱରୂପ, ଲଗଇନ୍‍ ପୃଷ୍ଠା ଦେଖାଯାଇଥିବା ସଂସ୍ଥାର ହୋଇନଥାଇପାରେ।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ବ୍ରାଉଜର୍‍ ଜରିଆରେ ଯେମିତିବି ହେଉ ଜାରି ରଖନ୍ତୁ"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ନେଟୱାର୍କ ବୁଷ୍ଟ"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ଏକ ଡାଟା ବୁଷ୍ଟ ପାଇଁ ସୁପାରିଶ କରେ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"ଆହୁରି ଭଲ ପରଫରମାନ୍ସ ପାଇଁ ଏକ ନେଟୱାର୍କ ବୁଷ୍ଟ କିଣନ୍ତୁ"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ବର୍ତ୍ତମାନ ନୁହେଁ"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"ପରିଚାଳନା କରନ୍ତୁ"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ଏକ ନେଟୱାର୍କ ବୁଷ୍ଟ କିଣନ୍ତୁ।"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pa/strings.xml b/packages/CarrierDefaultApp/res/values-pa/strings.xml
index 0f096ab1914d..6b15c1e6844d 100644
--- a/packages/CarrierDefaultApp/res/values-pa/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pa/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"ਤੁਸੀਂ ਜਿਸ ਨੈੱਟਵਰਕ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਹੇ ਹੋ ਉਸ ਵਿੱਚ ਸੁਰੱਖਿਆ ਸਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ।"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ਉਦਾਹਰਣ ਵੱਜੋਂ, ਲੌਗ-ਇਨ ਪੰਨਾ ਦਿਖਾਈ ਗਈ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਨਹੀਂ ਹੋ ਸਕਦਾ ਹੈ।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ਬ੍ਰਾਊਜ਼ਰ ਰਾਹੀਂ ਫਿਰ ਵੀ ਜਾਰੀ ਰੱਖੋ"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ਨੈੱਟਵਰਕ ਬੂਸਟ"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s ਵੱਲੋਂ ਡਾਟਾ ਬੂਸਟ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"ਬਿਹਤਰ ਕਾਰਗੁਜ਼ਾਰੀ ਲਈ ਨੈੱਟਵਰਕ ਬੂਸਟ ਖਰੀਦੋ"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ਹੁਣੇ ਨਹੀਂ"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ਨੈੱਟਵਰਕ ਬੂਸਟ ਖਰੀਦੋ।"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pl/strings.xml b/packages/CarrierDefaultApp/res/values-pl/strings.xml
index 08bc76731a43..86306a29b4a3 100644
--- a/packages/CarrierDefaultApp/res/values-pl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pl/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"W sieci, z którą próbujesz się połączyć, występują problemy z zabezpieczeniami."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Na przykład strona logowania może nie należeć do wyświetlanej organizacji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Kontynuuj mimo to w przeglądarce"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Wzmocnienie sygnału"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s zaleca wzmocnienie transmisji danych"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Kup wzmocnienie sygnału, aby zwiększyć skuteczność sieci"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Nie teraz"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Zarządzaj"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Kup wzmocnienie sygnału"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
index 23b4152b231d..1138a8bf59d9 100644
--- a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"A rede à qual você está tentando se conectar tem problemas de segurança."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Aumento de rede"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomenda um aumento de dados"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Aumente a rede para ter um desempenho melhor"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Agora não"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gerenciar"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Comprar um aumento de rede."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt/strings.xml b/packages/CarrierDefaultApp/res/values-pt/strings.xml
index 23b4152b231d..1138a8bf59d9 100644
--- a/packages/CarrierDefaultApp/res/values-pt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"A rede à qual você está tentando se conectar tem problemas de segurança."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Aumento de rede"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomenda um aumento de dados"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Aumente a rede para ter um desempenho melhor"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Agora não"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gerenciar"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Comprar um aumento de rede."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ro/strings.xml b/packages/CarrierDefaultApp/res/values-ro/strings.xml
index 165952cb7e4c..4a9d57c2bbe5 100644
--- a/packages/CarrierDefaultApp/res/values-ro/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ro/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Rețeaua la care încercați să vă conectați are probleme de securitate."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"De exemplu, este posibil ca pagina de conectare să nu aparțină organizației afișate."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuă oricum prin browser"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Pachet de date"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomandă un pachet de date"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Cumpără un pachet de date pentru o performanță mai bună"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Nu acum"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gestionează"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Cumpără un pachet de date."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ru/strings.xml b/packages/CarrierDefaultApp/res/values-ru/strings.xml
index 77ce91fecd4b..4fd6ffbaacf8 100644
--- a/packages/CarrierDefaultApp/res/values-ru/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ru/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Сеть, к которой вы хотите подключиться, небезопасна."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Например, страница входа в аккаунт может быть фиктивной."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Продолжить в браузере"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Ускорение сети"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s рекомендует использовать дополнительные данные"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Приобретите ускорение сети, чтобы повысить ее производительность"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Не сейчас"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Настроить"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Покупка ускорения сети."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-si/strings.xml b/packages/CarrierDefaultApp/res/values-si/strings.xml
index fe981ca7cbce..7dad968eb12d 100644
--- a/packages/CarrierDefaultApp/res/values-si/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-si/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"ඔබ සම්බන්ධ වීමට උත්සහ කරන ජාලයේ ආරක්ෂක ගැටළු ඇත."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"උදාහරණයක් ලෙස, පුරනය වන පිටුව පෙන්වා ඇති සංවිධානයට අයිති නැති විය හැක."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"කෙසේ වුවත් බ්‍රවුසරය හරහා ඉදිරියට යන්න"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"ජාල වැඩි කිරීම"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s දත්ත වැඩි කිරීමක් නිර්දේශ කරයි"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"වඩා හොඳ කාර්ය සාධනයක් සඳහා ජාල වැඩි වීමක් මිල දී ගන්න"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"දැන් නොවේ"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"කළමනාකරණය කරන්න"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ජාල වැඩි වීමක් මිල දී ගන්න."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sl/strings.xml b/packages/CarrierDefaultApp/res/values-sl/strings.xml
index 1a0f74b931d6..66dec186e034 100644
--- a/packages/CarrierDefaultApp/res/values-sl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sl/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Omrežje, ki se mu poskušate pridružiti, ima varnostne težave."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Stran za prijavo na primer morda ne pripada prikazani organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vseeno nadaljuj v brskalniku"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Izboljšanje omrežja"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s priporoča izboljšanje prenosa podatkov"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Za boljše delovanje si zagotovite izboljšanje omrežja."</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Ne zdaj"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Upravljanje"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Nakup izboljšanja omrežja"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sq/strings.xml b/packages/CarrierDefaultApp/res/values-sq/strings.xml
index f6e19355ac8a..c0d430e17aee 100644
--- a/packages/CarrierDefaultApp/res/values-sq/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sq/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Rrjeti në të cilin po përpiqesh të bashkohesh ka probleme sigurie."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"për shembull, faqja e identifikimit mund të mos i përkasë organizatës së shfaqur."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vazhdo gjithsesi nëpërmjet shfletuesit"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Paketa e përforcimit të rrjetit"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s rekomandon një paketë përforcimi të të dhënave"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Bli një paketë përforcimi të rrjetit për një performancë më të mirë"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Jo tani"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Menaxho"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Bli një paketë përforcimi të rrjetit."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sr/strings.xml b/packages/CarrierDefaultApp/res/values-sr/strings.xml
index e615eadba6da..84db181b1af5 100644
--- a/packages/CarrierDefaultApp/res/values-sr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sr/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Мрежа којој покушавате да се придружите има безбедносних проблема."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"На пример, страница за пријављивање можда не припада приказаној организацији."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ипак настави преко прегледача"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Појачање мреже"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s препоручује повећање података"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Купите појачање мреже за бољи учинак"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Не сада"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Управљајте"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Купите појачање мреже."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sv/strings.xml b/packages/CarrierDefaultApp/res/values-sv/strings.xml
index 778663b66d76..5e8853a941f8 100644
--- a/packages/CarrierDefaultApp/res/values-sv/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sv/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Nätverket du försöker ansluta till har säkerhetsproblem."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Det kan t.ex. hända att inloggningssidan inte tillhör den organisation som visas."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Fortsätt ändå via webbläsaren"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Nätverksboost"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s rekommenderar en databoost"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Köp en nätverksboost för bättre resultat"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Inte nu"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Hantera"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Köp en nätverksboost."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-sw/strings.xml b/packages/CarrierDefaultApp/res/values-sw/strings.xml
index 4f0745cec6b7..c99eb138c067 100644
--- a/packages/CarrierDefaultApp/res/values-sw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sw/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Mtandao unaojaribu kujiunga nao una matatizo ya usalama."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Kwa mfano, ukurasa wa kuingia katika akaunti unaweza usiwe unamilikiwa na shirika lililoonyeshwa."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Endelea hata hivyo kupitia kivinjari"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Kuimarisha mtandao"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s inapendekeza kuimarisha data"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Nunua kifaa cha kuimarisha mtandao kwa utendaji bora zaidi"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Si sasa"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Dhibiti"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Nunua kifaa cha kuimarisha mtandao."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ta/strings.xml b/packages/CarrierDefaultApp/res/values-ta/strings.xml
index a1d29286d060..6f7f4800ae79 100644
--- a/packages/CarrierDefaultApp/res/values-ta/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ta/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"நீங்கள் சேர முயலும் நெட்வொர்க்கில் பாதுகாப்புச் சிக்கல்கள் உள்ளன."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"எடுத்துக்காட்டாக, உள்நுழைவுப் பக்கமானது காட்டப்படும் அமைப்பிற்குச் சொந்தமானதாக இல்லாமல் இருக்கலாம்."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"பரவாயில்லை, உலாவி வழியாகத் தொடர்க"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"நெட்வொர்க் பூஸ்ட்"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"டேட்டா பூஸ்ட்டை %s பரிந்துரைக்கிறது"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"சிறப்பான செயல்திறனுக்கு நெட்வொர்க் பூஸ்ட்டை வாங்கவும்"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"இப்போது வேண்டாம்"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"நிர்வகியுங்கள்"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"நெட்வொர்க் பூஸ்ட்டை வாங்குங்கள்."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-te/strings.xml b/packages/CarrierDefaultApp/res/values-te/strings.xml
index 71399030c4b1..d1e49ca40b7c 100644
--- a/packages/CarrierDefaultApp/res/values-te/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-te/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"మీరు చేరడానికి ప్రయత్నిస్తున్న నెట్‌వర్క్ భద్రతా సమస్యలను కలిగి ఉంది."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ఉదాహరణకు, లాగిన్ పేజీ చూపిన సంస్థకు చెందినది కాకపోవచ్చు."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ఏదేమైనా బ్రౌజర్ ద్వారా కొనసాగించు"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"నెట్‌వర్క్ బూస్ట్"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"డేటా బూస్ట్‌ను %s సిఫార్సు చేస్తోంది"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"మెరుగైన పనితీరు కోసం నెట్‌వర్క్ బూస్ట్‌ను కొనుగోలు చేయండి"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ఇప్పుడు కాదు"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"మేనేజ్ చేయండి"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"నెట్‌వర్క్ బూస్ట్‌ను కొనుగోలు చేయండి."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-th/strings.xml b/packages/CarrierDefaultApp/res/values-th/strings.xml
index 5c63bb1bbecd..39889959728b 100644
--- a/packages/CarrierDefaultApp/res/values-th/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-th/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"เครือข่ายที่คุณพยายามเข้าร่วมมีปัญหาด้านความปลอดภัย"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"ตัวอย่างเช่น หน้าเข้าสู่ระบบอาจไม่ใช่ขององค์กรที่แสดงไว้"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ดำเนินการต่อผ่านเบราว์เซอร์"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"เพิ่มประสิทธิภาพเครือข่าย"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s แนะนำให้เพิ่มอินเทอร์เน็ตมือถือ"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"ซื้อการเพิ่มประสิทธิภาพเครือข่ายเพื่อการทำงานที่ดียิ่งขึ้น"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ไว้ทีหลัง"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"จัดการ"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"ซื้อการเพิ่มประสิทธิภาพเครือข่าย"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-tl/strings.xml b/packages/CarrierDefaultApp/res/values-tl/strings.xml
index 9e320c88e9eb..6375a9332d28 100644
--- a/packages/CarrierDefaultApp/res/values-tl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-tl/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"May mga isyu sa seguridad ang network na sinusubukan mong salihan."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Halimbawa, maaaring hindi pag-aari ng ipinapakitang organisasyon ang page ng login."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Magpatuloy pa rin sa pamamagitan ng browser"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Network boost"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"Nagrerekomenda ng data boost ang %s"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Bumili ng network boost para sa mas mahusay na performance"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Huwag muna"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Pamahalaan"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Bumili ng network boost."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-tr/strings.xml b/packages/CarrierDefaultApp/res/values-tr/strings.xml
index 63616ccab453..72808e681bcc 100644
--- a/packages/CarrierDefaultApp/res/values-tr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-tr/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Katılmaya çalıştığınız ağda güvenlik sorunları var."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Örneğin, giriş sayfası, gösterilen kuruluşa ait olmayabilir."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Yine de tarayıcıyla devam et"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Ağ güçlendirme"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s veri güçlendirme öneriyor"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Daha iyi performans için ağ güçlendirme satın alın"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Şimdi değil"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Yönet"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Ağ güçlendirme satın alın."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-uk/strings.xml b/packages/CarrierDefaultApp/res/values-uk/strings.xml
index bd4432711ddd..2b301649c228 100644
--- a/packages/CarrierDefaultApp/res/values-uk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-uk/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"У мережі, до якої ви намагаєтеся під’єднатись, є проблеми з безпекою."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Наприклад, сторінка входу може не належати вказаній організації."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Усе одно продовжити у веб-переглядачі"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Покращення характеристик мережі"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s рекомендує придбати покращення характеристик мережі"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Придбайте покращення характеристик мережі, щоб підвищити продуктивність"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Не зараз"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Керувати"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Придбайте покращення характеристик мережі."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml
index 3294cf5723c5..104f8068f9a5 100644
--- a/packages/CarrierDefaultApp/res/values-ur/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"آپ جس نیٹ ورک میں شامل ہونے کی کوشش کر رہے ہیں، اس میں سیکیورٹی کے مسائل ہیں۔"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"مثال کے طور پر ہو سکتا ہے کہ لاگ ان صفحہ دکھائی گئی تنظیم سے تعلق نہ رکھتا ہو۔"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"نیٹ ورک بوسٹ"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"‏%s ڈیٹا بوسٹ کی تجویز کرتا ہے"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"بہتر کارکردگی کے لیے نیٹ ورک بوسٹ خریدیں"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"ابھی نہیں"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"نظم کریں"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"نیٹ ورک بوسٹ خریدیں۔"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-uz/strings.xml b/packages/CarrierDefaultApp/res/values-uz/strings.xml
index 4eca545ffd87..a4eb37713dae 100644
--- a/packages/CarrierDefaultApp/res/values-uz/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-uz/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Siz ulanmoqchi bo‘lgan tarmoqda xavfsizlik bilan bog‘liq muammolar mavjud."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Masalan, tizimga kirish sahifasi ko‘rsatilgan tashkilotga tegishli bo‘lmasligi mumkin."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Brauzerda davom ettirish"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Tarmoq kuchaytirgichi"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s maʼlumotlarni kuchaytirishni tavsiya qiladi"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Yaxshiroq ishlash uchun tarmoq kuchaytirgichini sotib oling"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Hozir emas"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Boshqarish"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Tarmoq kuchaytirgichini sotib oling."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-vi/strings.xml b/packages/CarrierDefaultApp/res/values-vi/strings.xml
index d8f15e864818..6f6a314735b2 100644
--- a/packages/CarrierDefaultApp/res/values-vi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-vi/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"Mạng mà bạn đang cố gắng tham gia có vấn đề về bảo mật."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Ví dụ: trang đăng nhập có thể không thuộc về tổ chức được hiển thị."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vẫn tiếp tục qua trình duyệt"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"Tăng tốc độ mạng"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s đề xuất tăng tốc độ dữ liệu"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"Mua gói tăng tốc độ mạng để cải thiện hiệu suất"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Để sau"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Quản lý"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"Mua gói tăng tốc độ mạng."</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
index 4ce19f5d644c..a92278d80493 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"您尝试加入的网络存在安全问题。"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"例如,登录页面可能并不属于页面上显示的单位。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"仍然通过浏览器继续操作"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"网络加速"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"%s建议提升移动网络速度"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"购买网络加速服务,以获得更好的效果"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"以后再说"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"管理"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"购买网络加速服务。"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
index f019beb06a6c..959b497d20e9 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"您正在嘗試加入的網絡有安全性問題。"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"例如,登入頁面可能並不屬於所顯示的機構。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"網絡強化"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"「%s」建議購買流動數據強化"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"購買網絡強化以提升效能"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"暫時不要"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"管理"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"購買網絡強化。"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
index 32724b5ae772..29acabfba862 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
@@ -14,16 +14,10 @@
<string name="ssl_error_warning" msgid="3127935140338254180">"你嘗試加入的網路有安全性問題。"</string>
<string name="ssl_error_example" msgid="6188711843183058764">"例如,登入網頁中顯示的機構可能並非該網頁實際隸屬的機構。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string>
- <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
- <skip />
- <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
- <skip />
- <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
- <skip />
- <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
- <skip />
- <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
- <skip />
+ <string name="network_boost_notification_channel" msgid="5430986172506159199">"網路增強"</string>
+ <string name="network_boost_notification_title" msgid="8226368121348880044">"「%s」建議購買行動數據增強"</string>
+ <string name="network_boost_notification_detail" msgid="3812434025544196192">"購買網路增強以提升效能"</string>
+ <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"暫時不要"</string>
+ <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"管理"</string>
+ <string name="slice_purchase_app_label" msgid="915654761797446390">"購買網路增強。"</string>
</resources>
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
index b322b8bd95bb..367ae06adfc7 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
@@ -175,7 +175,9 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
&& isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED)
&& isPendingIntentValid(intent,
SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION)
- && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_SUCCESS);
+ && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_SUCCESS)
+ && isPendingIntentValid(intent,
+ SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN);
}
private static boolean isPendingIntentValid(@NonNull Intent intent, @NonNull String extra) {
@@ -208,6 +210,8 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
case SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION:
return "not default data subscription";
case SlicePurchaseController.EXTRA_INTENT_SUCCESS: return "success";
+ case SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN:
+ return "notification shown";
default: {
loge("Unknown pending intent extra: " + extra);
return "unknown(" + extra + ")";
@@ -220,7 +224,7 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
logd("onReceive intent: " + intent.getAction());
switch (intent.getAction()) {
case SlicePurchaseController.ACTION_START_SLICE_PURCHASE_APP:
- onDisplayBoosterNotification(context, intent);
+ onDisplayNetworkBoostNotification(context, intent);
break;
case SlicePurchaseController.ACTION_SLICE_PURCHASE_APP_RESPONSE_TIMEOUT:
onTimeout(context, intent);
@@ -233,7 +237,8 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
}
}
- private void onDisplayBoosterNotification(@NonNull Context context, @NonNull Intent intent) {
+ private void onDisplayNetworkBoostNotification(@NonNull Context context,
+ @NonNull Intent intent) {
if (!isIntentValid(intent)) {
sendSlicePurchaseAppResponse(intent,
SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED);
@@ -280,10 +285,12 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
int capability = intent.getIntExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
SlicePurchaseController.PREMIUM_CAPABILITY_INVALID);
- logd("Display the booster notification for capability "
+ logd("Display the network boost notification for capability "
+ TelephonyManager.convertPremiumCapabilityToString(capability));
context.getSystemService(NotificationManager.class).notifyAsUser(
NETWORK_BOOST_NOTIFICATION_TAG, capability, notification, UserHandle.ALL);
+ sendSlicePurchaseAppResponse(intent,
+ SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN);
}
/**
@@ -338,7 +345,7 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
+ " timed out.");
if (sSlicePurchaseActivities.get(capability) == null) {
// Notification is still active
- logd("Closing booster notification since the user did not respond in time.");
+ logd("Closing network boost notification since the user did not respond in time.");
context.getSystemService(NotificationManager.class).cancelAsUser(
NETWORK_BOOST_NOTIFICATION_TAG, capability, UserHandle.ALL);
} else {
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
index 5765e5b956a9..ab99a76902d9 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
@@ -64,6 +64,7 @@ public class SlicePurchaseBroadcastReceiverTest {
@Mock PendingIntent mCanceledIntent;
@Mock PendingIntent mContentIntent1;
@Mock PendingIntent mContentIntent2;
+ @Mock PendingIntent mNotificationShownIntent;
@Mock Context mContext;
@Mock Resources mResources;
@Mock NotificationManager mNotificationManager;
@@ -136,7 +137,7 @@ public class SlicePurchaseBroadcastReceiverTest {
}
@Test
- public void testDisplayBoosterNotification() {
+ public void testDisplayNetworkBoostNotification() throws Exception {
// set up intent
doReturn(SlicePurchaseController.ACTION_START_SLICE_PURCHASE_APP).when(mIntent).getAction();
doReturn(PHONE_ID).when(mIntent).getIntExtra(
@@ -148,11 +149,17 @@ public class SlicePurchaseBroadcastReceiverTest {
doReturn(TAG).when(mIntent).getStringExtra(
eq(SlicePurchaseController.EXTRA_REQUESTING_APP_NAME));
- // set up pending intent
+ // set up pending intents
doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mPendingIntent).getCreatorPackage();
doReturn(true).when(mPendingIntent).isBroadcast();
doReturn(mPendingIntent).when(mIntent).getParcelableExtra(
anyString(), eq(PendingIntent.class));
+ doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mNotificationShownIntent)
+ .getCreatorPackage();
+ doReturn(true).when(mNotificationShownIntent).isBroadcast();
+ doReturn(mNotificationShownIntent).when(mIntent).getParcelableExtra(
+ eq(SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN),
+ eq(PendingIntent.class));
// set up notification
doReturn(mResources).when(mContext).getResources();
@@ -185,8 +192,10 @@ public class SlicePurchaseBroadcastReceiverTest {
assertEquals(2, notification.actions.length);
assertEquals(mCanceledIntent, notification.actions[0].actionIntent);
assertEquals(mContentIntent2, notification.actions[1].actionIntent);
- }
+ // verify SlicePurchaseController was notified
+ verify(mNotificationShownIntent).send();
+ }
@Test
public void testNotificationCanceled() {
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_permission_microphone.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_microphone.xml
new file mode 100644
index 000000000000..161e4e6e6391
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_microphone.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@android:color/system_accent1_200">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,14Q10.75,14 9.875,13.125Q9,12.25 9,11V5Q9,3.75 9.875,2.875Q10.75,2 12,2Q13.25,2 14.125,2.875Q15,3.75 15,5V11Q15,12.25 14.125,13.125Q13.25,14 12,14ZM12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8ZM11,21V17.925Q8.4,17.575 6.7,15.6Q5,13.625 5,11H7Q7,13.075 8.463,14.537Q9.925,16 12,16Q14.075,16 15.538,14.537Q17,13.075 17,11H19Q19,13.625 17.3,15.6Q15.6,17.575 13,17.925V21ZM12,12Q12.425,12 12.713,11.712Q13,11.425 13,11V5Q13,4.575 12.713,4.287Q12.425,4 12,4Q11.575,4 11.288,4.287Q11,4.575 11,5V11Q11,11.425 11.288,11.712Q11.575,12 12,12Z"/>
+</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
new file mode 100644
index 000000000000..5f8d566f986c
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="160"
+ android:viewportWidth="160" >
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="M69.48,83.33A26.97,24.46 0,0 1,42.92 107.8,26.97 24.46,0 0,1 15.56,84.07 26.97,24.46 0,0 1,41.29 58.9,26.97 24.46,0 0,1 69.43,81.86"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="m143.73,83.58a26.97,24.46 0,0 1,-26.56 24.46,26.97 24.46,0 0,1 -27.36,-23.72 26.97,24.46 0,0 1,25.73 -25.18,26.97 24.46,0 0,1 28.14,22.96"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="m69.42,82.98c20.37,-0.25 20.37,-0.25 20.37,-0.25"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="M15.37,83.78 L1.9,56.83"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="M143.67,82.75C154.48,57.9 154.48,58.04 154.48,58.04"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_permission_microphone.xml b/packages/CompanionDeviceManager/res/drawable/ic_permission_microphone.xml
new file mode 100644
index 000000000000..eca625d715a0
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_permission_microphone.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@android:color/system_accent1_600">
+ <path android:fillColor="@android:color/white" android:pathData="M12,14Q10.75,14 9.875,13.125Q9,12.25 9,11V5Q9,3.75 9.875,2.875Q10.75,2 12,2Q13.25,2 14.125,2.875Q15,3.75 15,5V11Q15,12.25 14.125,13.125Q13.25,14 12,14ZM12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8Q12,8 12,8ZM11,21V17.925Q8.4,17.575 6.7,15.6Q5,13.625 5,11H7Q7,13.075 8.463,14.537Q9.925,16 12,16Q14.075,16 15.538,14.537Q17,13.075 17,11H19Q19,13.625 17.3,15.6Q15.6,17.575 13,17.925V21ZM12,12Q12.425,12 12.713,11.712Q13,11.425 13,11V5Q13,4.575 12.713,4.287Q12.425,4 12,4Q11.575,4 11.288,4.287Q11,4.575 11,5V11Q11,11.425 11.288,11.712Q11.575,12 12,12Z"/>
+</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
new file mode 100644
index 000000000000..7295e78b16cb
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@android:color/system_accent1_600">
+ <path
+ android:pathData="M6.2529,18.5H16.2529V17.5H18.2529V21.5C18.2529,22.6 17.3529,23.5 16.2529,23.5H6.2529C5.1529,23.5 4.2529,22.6 4.2529,21.5V3.5C4.2529,2.4 5.1529,1.51 6.2529,1.51L16.2529,1.5C17.3529,1.5 18.2529,2.4 18.2529,3.5V7.5H16.2529V6.5H6.2529V18.5ZM16.2529,3.5H6.2529V4.5H16.2529V3.5ZM6.2529,21.5V20.5H16.2529V21.5H6.2529ZM12.6553,9.4049C12.6553,8.8526 13.103,8.4049 13.6553,8.4049H20.5254C21.0776,8.4049 21.5254,8.8526 21.5254,9.4049V14.6055C21.5254,15.1578 21.0776,15.6055 20.5254,15.6055H14.355L12.6553,17.0871V9.4049Z"
+ android:fillColor="#3C4043"
+ android:fillType="evenOdd"/>
+</vector> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 97201e203463..3b215415a460 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -36,6 +36,18 @@
<!-- Description of the privileges the application will get if associated with the companion device of WATCH profile for singleDevice(type) [CHAR LIMIT=NONE] -->
<string name="summary_watch_single_device">The app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to interact with these permissions:</string>
+ <!-- TODO(b/256140614) To replace all glasses related strings with final versions -->
+ <!-- ================= DEVICE_PROFILE_GLASSES ================= -->
+
+ <!-- The name of the "glasses" device type [CHAR LIMIT=30] -->
+ <string name="profile_name_glasses">glasses</string>
+
+ <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile (type) [CHAR LIMIT=NONE] -->
+ <string name="summary_glasses">This app is needed to manage your <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to access your Phone, SMS, Contacts, Microphone and Nearby devices permissions.</string>
+
+ <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile for singleDevice(type) [CHAR LIMIT=NONE] -->
+ <string name="summary_glasses_single_device">The app is needed to manage your <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with these permissions:</string>
+
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
<!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
@@ -69,6 +81,18 @@
<!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] -->
<string name="helper_summary_computer"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to access your phone\u2019s photos, media, and notifications</string>
+ <!-- TODO(b/256140614) To replace all nearby_device_streaming related strings with final versions -->
+ <!-- ================= DEVICE_PROFILE_NEARBY_DEVICE_STREAMING ================= -->
+
+ <!-- Confirmation for associating an application with a companion device of NEARBY_DEVICE_STREAMING profile (type) [CHAR LIMIT=NONE] -->
+ <string name="title_nearby_device_streaming">Allow &lt;strong&gt;<xliff:g id="app_name" example="NearbyStreamer">%1$s</xliff:g>&lt;/strong&gt; to perform this action from your phone</string>
+
+ <!-- Title of the helper dialog for NEARBY_DEVICE_STREAMING profile [CHAR LIMIT=30]. -->
+ <string name="helper_title_nearby_device_streaming">Cross-device services</string>
+
+ <!-- Description of the helper dialog for NEARBY_DEVICE_STREAMING profile. [CHAR LIMIT=NONE] -->
+ <string name="helper_summary_nearby_device_streaming"><xliff:g id="app_name" example="NearbyStreamerApp">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="NearbyDevice">%2$s</xliff:g> to stream content to nearby devices</string>
+
<!-- ================= null profile ================= -->
<!-- A noun for a companion device with unspecified profile (type) [CHAR LIMIT=30] -->
@@ -116,7 +140,10 @@
<!-- Calendar permission will be granted of corresponding profile [CHAR LIMIT=30] -->
<string name="permission_calendar">Calendar</string>
- <!-- Calendar permission will be granted of corresponding profile [CHAR LIMIT=30] -->
+ <!-- Microphone permission will be granted to corresponding profile [CHAR LIMIT=30] -->
+ <string name="permission_microphone">Microphone</string>
+
+ <!-- Nearby devices permission will be granted of corresponding profile [CHAR LIMIT=30] -->
<string name="permission_nearby_devices">Nearby devices</string>
<!-- Storage permission will be granted of corresponding profile [CHAR LIMIT=30] -->
@@ -128,6 +155,9 @@
<!-- Apps permission will be granted of corresponding profile [CHAR LIMIT=30] -->
<string name="permission_app_streaming">Apps</string>
+ <!-- Nearby_device_streaming permission will be granted to the corresponding profile [CHAR LIMIT=30] -->
+ <string name="permission_nearby_device_streaming">Nearby Device Streaming</string>
+
<!-- Description of phone permission of corresponding profile [CHAR LIMIT=NONE] -->
<string name="permission_phone_summary">Can access your phone number and network info. Required for making calls and VoIP, voicemail, call redirect, and editing call logs</string>
@@ -142,6 +172,10 @@
<!-- TODO(b/253644212) Need the description for calendar permission -->
<string name="permission_calendar_summary"></string>
+ <!-- Description of microphone permission of corresponding profile [CHAR LIMIT=NONE] -->
+ <!-- TODO(b/256140614) Need the description for microphone permission -->
+ <string name="permission_microphone_summary">Can record audio using the microphone</string>
+
<!-- Description of nearby devices' permission of corresponding profile [CHAR LIMIT=NONE] -->
<!-- TODO(b/253644212) Need the description for nearby devices' permission -->
<string name="permission_nearby_devices_summary"></string>
@@ -155,4 +189,8 @@
<!-- Description of storage permission of corresponding profile [CHAR LIMIT=NONE] -->
<string name="permission_storage_summary"></string>
+ <!-- Description of nearby_device_streaming permission of corresponding profile [CHAR LIMIT=NONE] -->
+ <!-- TODO(b/256140614) Need the description for nearby devices' permission -->
+ <string name="permission_nearby_device_streaming_summary">Stream content to a nearby device</string>
+
</resources>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 3a3a5d20b47c..49a633450629 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -19,6 +19,8 @@ package com.android.companiondevicemanager;
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.companion.CompanionDeviceManager.REASON_CANCELED;
import static android.companion.CompanionDeviceManager.REASON_DISCOVERY_TIMEOUT;
@@ -34,7 +36,9 @@ import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_APP_STREAMING;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CALENDAR;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CONTACTS;
+import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_MICROPHONE;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NEARBY_DEVICES;
+import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NEARBY_DEVICE_STREAMING;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NOTIFICATION;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_PHONE;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_SMS;
@@ -501,6 +505,12 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mPermissionTypes.addAll(Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_STORAGE));
break;
+ case DEVICE_PROFILE_NEARBY_DEVICE_STREAMING:
+ title = getHtmlFromResources(this, R.string.title_nearby_device_streaming,
+ deviceName);
+ mPermissionTypes.add(PERMISSION_NEARBY_DEVICE_STREAMING);
+ break;
+
default:
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
@@ -556,7 +566,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
}
final String deviceName = mSelectedDevice.getDisplayName();
- final String profileName = getString(R.string.profile_name_watch);
+ final String profileName;
final Spanned title;
final Spanned summary;
final Drawable profileIcon;
@@ -569,6 +579,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mSummary.setVisibility(View.GONE);
mConstraintList.setVisibility(View.GONE);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
+ profileName = getString(R.string.profile_name_watch);
title = getHtmlFromResources(this, R.string.confirmation_title, appLabel, deviceName);
summary = getHtmlFromResources(
this, R.string.summary_watch_single_device, profileName, appLabel);
@@ -579,6 +590,18 @@ public class CompanionDeviceActivity extends FragmentActivity implements
PERMISSION_CALENDAR, PERMISSION_NEARBY_DEVICES));
setupPermissionList();
+ } else if (deviceProfile.equals(DEVICE_PROFILE_GLASSES)) {
+ profileName = getString(R.string.profile_name_glasses);
+ title = getHtmlFromResources(this, R.string.confirmation_title, appLabel, profileName);
+ summary = getHtmlFromResources(
+ this, R.string.summary_glasses_single_device, profileName, appLabel);
+ profileIcon = getIcon(this, R.drawable.ic_glasses);
+
+ mPermissionTypes.addAll(Arrays.asList(
+ PERMISSION_PHONE, PERMISSION_SMS, PERMISSION_CONTACTS,
+ PERMISSION_MICROPHONE, PERMISSION_NEARBY_DEVICES));
+
+ setupPermissionList();
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
@@ -607,6 +630,10 @@ public class CompanionDeviceActivity extends FragmentActivity implements
profileName = getString(R.string.profile_name_watch);
summary = getHtmlFromResources(this, R.string.summary_watch, profileName, appLabel);
profileIcon = getIcon(this, R.drawable.ic_watch);
+ } else if (deviceProfile.equals(DEVICE_PROFILE_GLASSES)) {
+ profileName = getString(R.string.profile_name_glasses);
+ summary = getHtmlFromResources(this, R.string.summary_glasses, profileName, appLabel);
+ profileIcon = getIcon(this, R.drawable.ic_glasses);
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
index 804e7577366b..eae14a6ac175 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
@@ -18,6 +18,7 @@ package com.android.companiondevicemanager;
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING;
import static com.android.companiondevicemanager.Utils.getApplicationIcon;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
@@ -134,6 +135,14 @@ public class CompanionVendorHelperDialogFragment extends DialogFragment {
getContext(), R.string.helper_summary_computer, title, displayName);
break;
+ case DEVICE_PROFILE_NEARBY_DEVICE_STREAMING:
+ title = getHtmlFromResources(getContext(),
+ R.string.helper_title_nearby_device_streaming);
+ summary = getHtmlFromResources(
+ getContext(), R.string.helper_summary_nearby_device_streaming, title,
+ displayName);
+ break;
+
default:
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index 0ee94a2c3921..00c44d692782 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -50,6 +50,8 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
static final int PERMISSION_CONTACTS = 5;
static final int PERMISSION_CALENDAR = 6;
static final int PERMISSION_NEARBY_DEVICES = 7;
+ static final int PERMISSION_NEARBY_DEVICE_STREAMING = 8;
+ static final int PERMISSION_MICROPHONE = 9;
private static final Map<Integer, Integer> sTitleMap;
static {
@@ -62,6 +64,8 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
map.put(PERMISSION_CONTACTS, R.string.permission_contacts);
map.put(PERMISSION_CALENDAR, R.string.permission_calendar);
map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming);
+ map.put(PERMISSION_MICROPHONE, R.string.permission_microphone);
sTitleMap = unmodifiableMap(map);
}
@@ -76,6 +80,9 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
map.put(PERMISSION_CONTACTS, R.string.permission_contacts_summary);
map.put(PERMISSION_CALENDAR, R.string.permission_calendar_summary);
map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices_summary);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
+ R.string.permission_nearby_device_streaming_summary);
+ map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary);
sSummaryMap = unmodifiableMap(map);
}
@@ -90,6 +97,9 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
map.put(PERMISSION_CONTACTS, R.drawable.ic_permission_contacts);
map.put(PERMISSION_CALENDAR, R.drawable.ic_permission_calendar);
map.put(PERMISSION_NEARBY_DEVICES, R.drawable.ic_permission_nearby_devices);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
+ R.drawable.ic_permission_nearby_device_streaming);
+ map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone);
sIconMap = unmodifiableMap(map);
}
diff --git a/packages/CredentialManager/res/drawable/ic_face.xml b/packages/CredentialManager/res/drawable/ic_face.xml
deleted file mode 100644
index 16fe14495e9d..000000000000
--- a/packages/CredentialManager/res/drawable/ic_face.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!--TODO: Testing only icon. Remove later. -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- tools:ignore="VectorPath"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="#808080"
- android:pathData="M9.025,14.275Q8.5,14.275 8.125,13.9Q7.75,13.525 7.75,13Q7.75,12.475 8.125,12.1Q8.5,11.725 9.025,11.725Q9.575,11.725 9.938,12.1Q10.3,12.475 10.3,13Q10.3,13.525 9.938,13.9Q9.575,14.275 9.025,14.275ZM14.975,14.275Q14.425,14.275 14.062,13.9Q13.7,13.525 13.7,13Q13.7,12.475 14.062,12.1Q14.425,11.725 14.975,11.725Q15.5,11.725 15.875,12.1Q16.25,12.475 16.25,13Q16.25,13.525 15.875,13.9Q15.5,14.275 14.975,14.275ZM12,19.925Q15.325,19.925 17.625,17.625Q19.925,15.325 19.925,12Q19.925,11.4 19.85,10.85Q19.775,10.3 19.575,9.775Q19.05,9.9 18.538,9.962Q18.025,10.025 17.45,10.025Q15.2,10.025 13.188,9.062Q11.175,8.1 9.775,6.375Q8.975,8.3 7.5,9.712Q6.025,11.125 4.075,11.85Q4.075,11.9 4.075,11.925Q4.075,11.95 4.075,12Q4.075,15.325 6.375,17.625Q8.675,19.925 12,19.925ZM12,22.2Q9.9,22.2 8.038,21.4Q6.175,20.6 4.788,19.225Q3.4,17.85 2.6,15.988Q1.8,14.125 1.8,12Q1.8,9.875 2.6,8.012Q3.4,6.15 4.788,4.775Q6.175,3.4 8.038,2.6Q9.9,1.8 12,1.8Q14.125,1.8 15.988,2.6Q17.85,3.4 19.225,4.775Q20.6,6.15 21.4,8.012Q22.2,9.875 22.2,12Q22.2,14.125 21.4,15.988Q20.6,17.85 19.225,19.225Q17.85,20.6 15.988,21.4Q14.125,22.2 12,22.2Z"/>
-</vector> \ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/ic_manage_accounts.xml b/packages/CredentialManager/res/drawable/ic_manage_accounts.xml
deleted file mode 100644
index adad2f105d55..000000000000
--- a/packages/CredentialManager/res/drawable/ic_manage_accounts.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!--TODO: Testing only icon. Remove later. -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- tools:ignore="VectorPath"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="#808080"
- android:pathData="M16.1,21.2 L15.775,19.675Q15.5,19.55 15.25,19.425Q15,19.3 14.75,19.1L13.275,19.575L12.2,17.75L13.375,16.725Q13.325,16.4 13.325,16.112Q13.325,15.825 13.375,15.5L12.2,14.475L13.275,12.65L14.75,13.1Q15,12.925 15.25,12.787Q15.5,12.65 15.775,12.55L16.1,11.025H18.25L18.55,12.55Q18.825,12.65 19.075,12.8Q19.325,12.95 19.575,13.15L21.05,12.65L22.125,14.525L20.95,15.55Q21.025,15.825 21.013,16.137Q21,16.45 20.95,16.725L22.125,17.75L21.05,19.575L19.575,19.1Q19.325,19.3 19.075,19.425Q18.825,19.55 18.55,19.675L18.25,21.2ZM1.8,20.3V17.3Q1.8,16.375 2.275,15.613Q2.75,14.85 3.5,14.475Q4.775,13.825 6.425,13.362Q8.075,12.9 10,12.9Q10.2,12.9 10.4,12.9Q10.6,12.9 10.775,12.95Q9.925,14.85 10.062,16.738Q10.2,18.625 11.4,20.3ZM17.175,18.075Q17.975,18.075 18.55,17.487Q19.125,16.9 19.125,16.1Q19.125,15.3 18.55,14.725Q17.975,14.15 17.175,14.15Q16.375,14.15 15.788,14.725Q15.2,15.3 15.2,16.1Q15.2,16.9 15.788,17.487Q16.375,18.075 17.175,18.075ZM10,11.9Q8.25,11.9 7.025,10.662Q5.8,9.425 5.8,7.7Q5.8,5.95 7.025,4.725Q8.25,3.5 10,3.5Q11.75,3.5 12.975,4.725Q14.2,5.95 14.2,7.7Q14.2,9.425 12.975,10.662Q11.75,11.9 10,11.9Z"/>
-</vector> \ No newline at end of file
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index 377c13fb7881..a5482198a1f3 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Stoor in ’n ander plek"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Gebruik ’n ander toestel"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Stoor op ’n ander toestel"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"’n Maklike manier om veilig aan te meld"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gebruik jou vingerafdruk, gesig of skermslot om aan te meld met ’n unieke wagwoordsleutel wat nie vergeet of gesteel kan word nie. Kom meer te wete"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Kies waar om <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Kies waar om <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"skep jou wagwoordsleutels"</string>
<string name="save_your_password" msgid="6597736507991704307">"stoor jou wagwoord"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"stoor jou aanmeldinligting"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Stel ’n verstekwagwoordbestuurder om jou wagwoorde en wagwoordsleutels te stoor, en meld volgende keer vinniger aan."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Skep ’n wagwoordsleutel in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Stoor jou wagwoord in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Stoor jou aanmeldinligting in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"wagwoordsleutel"</string>
<string name="password" msgid="6738570945182936667">"wagwoord"</string>
<string name="sign_ins" msgid="4710739369149469208">"aanmeldings"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Skep wagwoordsleutel in"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Stoor wagwoord in"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Stoor aanmelding in"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Skep ’n wagwoordsleutel op ’n ander toestel?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gebruik <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> vir al jou aanmeldings?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Hierdie wagwoordbestuurder sal jou wagwoorde en wagwoordsleutels berg om jou te help om maklik aan te meld."</string>
<string name="set_as_default" msgid="4415328591568654603">"Stel as verstek"</string>
<string name="use_once" msgid="9027366575315399714">"Gebruik een keer"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wagwoorde, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> wagwoordsleutels"</string>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
index b80fe2cee53a..6fdc696bcfb2 100644
--- a/packages/CredentialManager/res/values-am/strings.xml
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -3,45 +3,34 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- no translation found for app_name (4539824758261855508) -->
<skip />
- <!-- no translation found for string_cancel (6369133483981306063) -->
- <skip />
- <!-- no translation found for string_continue (1346732695941131882) -->
- <skip />
- <!-- no translation found for string_create_in_another_place (1033635365843437603) -->
- <skip />
- <!-- no translation found for string_save_to_another_place (7590325934591079193) -->
- <skip />
- <!-- no translation found for string_use_another_device (8754514926121520445) -->
- <skip />
+ <string name="string_cancel" msgid="6369133483981306063">"ይቅር"</string>
+ <string name="string_continue" msgid="1346732695941131882">"ቀጥል"</string>
+ <string name="string_create_in_another_place" msgid="1033635365843437603">"በሌላ ቦታ ውስጥ ይፍጠሩ"</string>
+ <string name="string_save_to_another_place" msgid="7590325934591079193">"ወደ ሌላ ቦታ ያስቀምጡ"</string>
+ <string name="string_use_another_device" msgid="8754514926121520445">"ሌላ መሣሪያ ይጠቀሙ"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"ወደ ሌላ መሣሪያ ያስቀምጡ"</string>
- <!-- no translation found for passkey_creation_intro_title (402553911484409884) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
<skip />
- <!-- no translation found for passkey_creation_intro_body (7493320456005579290) -->
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
<skip />
- <!-- no translation found for choose_provider_title (7245243990139698508) -->
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
- <skip />
- <!-- no translation found for save_your_password (6597736507991704307) -->
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
<skip />
- <!-- no translation found for save_your_sign_in_info (7213978049817076882) -->
+ <string name="choose_provider_title" msgid="7245243990139698508">"የት <xliff:g id="CREATETYPES">%1$s</xliff:g> እንደሚሆን ይምረጡ"</string>
+ <!-- no translation found for create_your_passkeys (8901224153607590596) -->
<skip />
+ <string name="save_your_password" msgid="6597736507991704307">"የይለፍ ቃልዎን ያስቀምጡ"</string>
+ <string name="save_your_sign_in_info" msgid="7213978049817076882">"የመግቢያ መረጃዎን ያስቀምጡ"</string>
<!-- no translation found for choose_provider_body (8045759834416308059) -->
<skip />
- <!-- no translation found for choose_create_option_passkey_title (4146408187146573131) -->
- <skip />
- <!-- no translation found for choose_create_option_password_title (8812546498357380545) -->
- <skip />
- <!-- no translation found for choose_create_option_sign_in_title (6318246378475961834) -->
- <skip />
- <!-- no translation found for choose_create_option_description (4419171903963100257) -->
- <skip />
- <!-- no translation found for passkey (632353688396759522) -->
- <skip />
- <!-- no translation found for password (6738570945182936667) -->
- <skip />
- <!-- no translation found for sign_ins (4710739369149469208) -->
- <skip />
+ <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"በ<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ውስጥ የይለፍ ቁልፍ ይፈጠር?"</string>
+ <string name="choose_create_option_password_title" msgid="8812546498357380545">"የይለፍ ቃልዎ ወደ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ይቀመጥ?"</string>
+ <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"የመግቢያ መረጃዎ ወደ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ይቀመጥ?"</string>
+ <string name="choose_create_option_description" msgid="4419171903963100257">"የእርስዎን <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> በማንኛውም መሣሪያ ላይ መጠቀም ይችላሉ። ለ<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ወደ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ተቀምጧል"</string>
+ <string name="passkey" msgid="632353688396759522">"የይለፍ ቁልፍ"</string>
+ <string name="password" msgid="6738570945182936667">"የይለፍ ቃል"</string>
+ <string name="sign_ins" msgid="4710739369149469208">"መግቢያዎች"</string>
<!-- no translation found for create_passkey_in_title (2714306562710897785) -->
<skip />
<!-- no translation found for save_password_to_title (3450480045270186421) -->
@@ -50,54 +39,31 @@
<skip />
<!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
<skip />
- <!-- no translation found for use_provider_for_all_title (4201020195058980757) -->
- <skip />
+ <string name="use_provider_for_all_title" msgid="4201020195058980757">"ለሁሉም መግቢያዎችዎ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ን ይጠቀሙ?"</string>
<!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
<skip />
- <!-- no translation found for set_as_default (4415328591568654603) -->
- <skip />
- <!-- no translation found for use_once (9027366575315399714) -->
- <skip />
- <!-- no translation found for more_options_usage_passwords_passkeys (4794903978126339473) -->
- <skip />
- <!-- no translation found for more_options_usage_passwords (1632047277723187813) -->
- <skip />
- <!-- no translation found for more_options_usage_passkeys (5390320437243042237) -->
- <skip />
+ <string name="set_as_default" msgid="4415328591568654603">"እንደ ነባሪ ያዋቅሩ"</string>
+ <string name="use_once" msgid="9027366575315399714">"አንዴ ይጠቀሙ"</string>
+ <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> የይለፍ ቃሎች፣ <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> የይለፍ ቁልፎች"</string>
+ <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> የይለፍ ቃሎች"</string>
+ <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> የይለፍ ቁልፎች"</string>
<!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
<skip />
- <!-- no translation found for another_device (5147276802037801217) -->
- <skip />
- <!-- no translation found for other_password_manager (565790221427004141) -->
- <skip />
- <!-- no translation found for close_sheet (1393792015338908262) -->
- <skip />
- <!-- no translation found for accessibility_back_arrow_button (3233198183497842492) -->
- <skip />
- <!-- no translation found for get_dialog_title_use_passkey_for (6236608872708021767) -->
- <skip />
- <!-- no translation found for get_dialog_title_use_sign_in_for (5283099528915572980) -->
- <skip />
- <!-- no translation found for get_dialog_title_choose_sign_in_for (1361715440877613701) -->
- <skip />
- <!-- no translation found for get_dialog_use_saved_passkey_for (4618100798664888512) -->
- <skip />
- <!-- no translation found for get_dialog_button_label_no_thanks (8114363019023838533) -->
- <skip />
- <!-- no translation found for get_dialog_button_label_continue (6446201694794283870) -->
- <skip />
- <!-- no translation found for get_dialog_title_sign_in_options (2092876443114893618) -->
- <skip />
- <!-- no translation found for get_dialog_heading_for_username (3456868514554204776) -->
- <skip />
- <!-- no translation found for get_dialog_heading_locked_password_managers (8911514851762862180) -->
- <skip />
- <!-- no translation found for locked_credential_entry_label_subtext (9213450912991988691) -->
- <skip />
- <!-- no translation found for get_dialog_heading_manage_sign_ins (3522556476480676782) -->
- <skip />
- <!-- no translation found for get_dialog_heading_from_another_device (1166697017046724072) -->
- <skip />
- <!-- no translation found for get_dialog_option_headline_use_a_different_device (8201578814988047549) -->
- <skip />
+ <string name="another_device" msgid="5147276802037801217">"ሌላ መሣሪያ"</string>
+ <string name="other_password_manager" msgid="565790221427004141">"ሌሎች የይለፍ ቃል አስተዳዳሪዎች"</string>
+ <string name="close_sheet" msgid="1393792015338908262">"ሉህን ዝጋ"</string>
+ <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ወደ ቀዳሚው ገፅ ይመለሱ"</string>
+ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"የተቀመጠ የይለፍ ቁልፍዎን ለ<xliff:g id="APP_NAME">%1$s</xliff:g> ይጠቀሙ?"</string>
+ <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"የተቀመጠ መግቢያዎን ለ<xliff:g id="APP_NAME">%1$s</xliff:g> ይጠቀሙ?"</string>
+ <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"ለ<xliff:g id="APP_NAME">%1$s</xliff:g> የተቀመጠ መግቢያ ይጠቀሙ"</string>
+ <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"በሌላ መንገድ ይግቡ"</string>
+ <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"አይ አመሰግናለሁ"</string>
+ <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ቀጥል"</string>
+ <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"የመግቢያ አማራጮች"</string>
+ <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"ለ<xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"የተቆለፉ የሚስጥር ቁልፍ አስተዳዳሪዎች"</string>
+ <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"ለመክፈት መታ ያድርጉ"</string>
+ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"መግቢያዎችን ያስተዳድሩ"</string>
+ <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ከሌላ መሣሪያ"</string>
+ <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"የተለየ መሣሪያ ይጠቀሙ"</string>
</resources>
diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml
index a5c85c5281b2..6a2c9a157313 100644
--- a/packages/CredentialManager/res/values-ar/strings.xml
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"مدير بيانات الاعتماد"</string>
<string name="string_cancel" msgid="6369133483981306063">"إلغاء"</string>
<string name="string_continue" msgid="1346732695941131882">"متابعة"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"الإنشاء في مكان آخر"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"الحفظ في مكان آخر"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"استخدام جهاز آخر"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"الحفظ على جهاز آخر"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"طريقة بسيطة لتسجيل الدخول بأمان"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"استخدِم بصمة إصبعك أو وجهك أو قفل الشاشة لتسجيل الدخول باستخدام مفتاح مرور فريد لا يمكن نسيانه أو سرقته. مزيد من المعلومات"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"اختيار مكان <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"اختيار مكان <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"إنشاء مفاتيح مرورك"</string>
<string name="save_your_password" msgid="6597736507991704307">"حفظ كلمة المرور"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"حفظ معلومات تسجيل الدخول"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"يمكنك ضبط خدمة تلقائية لـ \"مدير كلمات المرور\" من أجل حفظ كلمات المرور ومفاتيح المرور وتسجيل الدخول بشكل أسرع في المرة القادمة."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"هل تريد إنشاء مفتاح مرور في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"؟"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"هل تريد حفظ كلمة مرورك في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"؟"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"هل تريد حفظ معلومات تسجيل الدخول في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"؟"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"مفتاح مرور"</string>
<string name="password" msgid="6738570945182936667">"كلمة المرور"</string>
<string name="sign_ins" msgid="4710739369149469208">"عمليات تسجيل الدخول"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"إنشاء مفتاح مرور في"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"حفظ كلمة المرور في"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"حفظ معلومات تسجيل الدخول في"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"هل تريد إنشاء مفتاح مرور في جهاز آخر؟"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"هل تريد استخدام \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\" لكل عمليات تسجيل الدخول؟"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"سيخزِّن \"مدير كلمات المرور\" هذا كلمات المرور ومفاتيح المرور لمساعدتك في تسجيل الدخول بسهولة."</string>
<string name="set_as_default" msgid="4415328591568654603">"ضبط الخيار كتلقائي"</string>
<string name="use_once" msgid="9027366575315399714">"الاستخدام مرة واحدة"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"عدد كلمات المرور هو <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>، و عدد مفاتيح المرور هو <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"عدد كلمات المرور: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"عدد مفاتيح المرور: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"مفتاح مرور"</string>
<string name="another_device" msgid="5147276802037801217">"جهاز آخر"</string>
<string name="other_password_manager" msgid="565790221427004141">"خدمات مدراء كلمات المرور الأخرى"</string>
<string name="close_sheet" msgid="1393792015338908262">"إغلاق ورقة البيانات"</string>
diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml
index 4d0ba6815947..7d3b5f84d147 100644
--- a/packages/CredentialManager/res/values-as/strings.xml
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"অন্য ঠাইত ছেভ কৰক"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"অন্য ডিভাইচ ব্যৱহাৰ কৰক"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"অন্য এটা ডিভাইচত ছেভ কৰক"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"সুৰক্ষিতভাৱে ছাইন ইন কৰাৰ এক সৰল উপায়"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"পাহৰি নোযোৱা অথবা চুৰি কৰিব নোৱৰা এটা অদ্বিতীয় পাছকী ব্যৱহাৰ কৰি ছাইন ইন কৰিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট, মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক। অধিক জানক"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"ক’ত <xliff:g id="CREATETYPES">%1$s</xliff:g> সেয়া বাছনি কৰক"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"ক’ত <xliff:g id="CREATETYPES">%1$s</xliff:g> সেয়া বাছনি কৰক"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"আপোনাৰ পাছকী সৃষ্টি কৰক"</string>
<string name="save_your_password" msgid="6597736507991704307">"আপোনাৰ পাছৱৰ্ড ছেভ কৰক"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"আপোনাৰ ছাইন ইন কৰাৰ তথ্য ছেভ কৰক"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"আপোনাৰ পাছৱৰ্ড আৰু পাছকী ছেভ কৰিবলৈ এটা ডিফ’ল্ট পাছৱৰ্ড পৰিচালক ছেট কৰক আৰু পৰৱৰ্তী বাৰ দ্ৰুতভাৱে ছাইন ইন কৰক।"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ত পাছকী সৃষ্টি কৰিবনে?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ত আপোনাৰ পাছৱৰ্ড ছেভ কৰিবনে?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ত আপোনাৰ ছাইন ইন কৰাৰ তথ্য ছেভ কৰিবনে?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"পাছকী"</string>
<string name="password" msgid="6738570945182936667">"পাছৱৰ্ড"</string>
<string name="sign_ins" msgid="4710739369149469208">"ছাইন-ইন"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ইয়াত পাছকী সৃষ্টি কৰক"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"ইয়াত পাছৱৰ্ড ছেভ কৰক"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ইয়াত ছাইন ইন কৰাৰ তথ্য ছেভ কৰক"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"অন্য এটা ডিভাইচত এটা পাছকী সৃষ্টি কৰিবনে?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"আপোনাৰ আটাইবোৰ ছাইন ইনৰ বাবে <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবনে?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"আপোনাক সহজে ছাইন ইন কৰাত সহায় কৰিবলৈ এই পাছৱৰ্ড পৰিচালকটোৱে আপোনাৰ পাছৱৰ্ড আৰু পাছকী ষ্ট’ৰ কৰিব।"</string>
<string name="set_as_default" msgid="4415328591568654603">"ডিফ’ল্ট হিচাপে ছেট কৰক"</string>
<string name="use_once" msgid="9027366575315399714">"এবাৰ ব্যৱহাৰ কৰক"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> টা পাছৱৰ্ড, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> টা পাছকী"</string>
diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml
index 14313f759b48..45af67bbdfbc 100644
--- a/packages/CredentialManager/res/values-az/strings.xml
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Başqa yerdə yadda saxlayın"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Digər cihaz istifadə edin"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Başqa cihazda yadda saxlayın"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Təhlükəsiz daxil olmağın sadə yolu"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Unutmaq və ya oğurlamaq mümkün olmayan unikal giriş açarı ilə daxil olmaq üçün barmaq izi, üz və ya ekran kilidindən istifadə edin. Ətraflı məlumat"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> üçün yer seçin"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> üçün yer seçin"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"giriş açarları yaradın"</string>
<string name="save_your_password" msgid="6597736507991704307">"parolunuzu yadda saxlayın"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"giriş məlumatınızı yadda saxlayın"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Parollarınızı və giriş açarlarınızı saxlamaq və növbəti dəfə daha sürətli daxil olmaq üçün defolt parol meneceri ayarlayın."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xidmətində giriş açarı yaradılsın?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Parol <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xidmətində saxlanılsın?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Giriş məlumatınız <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xidmətində saxlanılsın?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"giriş açarı"</string>
<string name="password" msgid="6738570945182936667">"parol"</string>
<string name="sign_ins" msgid="4710739369149469208">"girişlər"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Burada giriş açarı yaradın:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Parolu burada yadda saxlayın:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Girişi burada yadda saxlayın:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Başqa cihazda giriş açarı yaradılsın?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Bütün girişlər üçün <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> istifadə edilsin?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Bu parol meneceri asanlıqla daxil olmanıza kömək etmək üçün parollarınızı və giriş açarlarınızı saxlayacaq."</string>
<string name="set_as_default" msgid="4415328591568654603">"Defolt olaraq seçin"</string>
<string name="use_once" msgid="9027366575315399714">"Bir dəfə istifadə edin"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parol, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> giriş açarı"</string>
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
index c58ec141f01b..7a8e40d8633e 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Menadžer akreditiva"</string>
<string name="string_cancel" msgid="6369133483981306063">"Otkaži"</string>
<string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Napravi na drugom mestu"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Sačuvaj na drugom mestu"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Koristi drugi uređaj"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Sačuvaj na drugi uređaj"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednostavan način da se bezbedno prijavljujete"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Koristite otisak prsta, zaključavanje licem ili zaključavanje ekrana da biste se prijavili pomoću jedinstvenog pristupnog koda koji ne može da se zaboravi ili ukrade. Saznajte više"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite lokaciju za: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite lokaciju za: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"napravite pristupne kodove"</string>
<string name="save_your_password" msgid="6597736507991704307">"sačuvajte lozinku"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"sačuvajte podatke o prijavljivanju"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Podesite podrazumevani menadžer lozinki da biste sačuvali lozinke i pristupne kodove i sledeći put se prijavili brže."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Želite da napravite pristupni kôd kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Želite da sačuvate lozinku kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Želite da sačuvate podatke o prijavljivanju kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"pristupni kôd"</string>
<string name="password" msgid="6738570945182936667">"lozinka"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijavljivanja"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Napravite pristupni kôd u:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Sačuvajte lozinku na:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Sačuvajte podatke o prijavljivanju na:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Želite da napravite pristupni kôd na drugom uređaju?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite da za sva prijavljivanja koristite: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ovaj menadžer lozinki će čuvati lozinke i pristupne kodove da biste se lako prijavljivali."</string>
<string name="set_as_default" msgid="4415328591568654603">"Podesi kao podrazumevano"</string>
<string name="use_once" msgid="9027366575315399714">"Koristi jednom"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, pristupnih kodova:<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Pristupnih kodova: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Pristupni kôd"</string>
<string name="another_device" msgid="5147276802037801217">"Drugi uređaj"</string>
<string name="other_password_manager" msgid="565790221427004141">"Drugi menadžeri lozinki"</string>
<string name="close_sheet" msgid="1393792015338908262">"Zatvorite tabelu"</string>
diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml
index 3c23afd5101b..4b602444d100 100644
--- a/packages/CredentialManager/res/values-be/strings.xml
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Менеджар уліковых даных"</string>
<string name="string_cancel" msgid="6369133483981306063">"Скасаваць"</string>
<string name="string_continue" msgid="1346732695941131882">"Далей"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Стварыць у іншым месцы"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Захаваць у іншым месцы"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Скарыстаць іншую прыладу"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Захаваць на іншую прыладу"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Просты спосаб бяспечнага ўваходу"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Для ўваходу з унікальным ключом доступу, які нельга згубіць ці ўкрасці, можна скарыстаць адбітак пальца, распазнаванне твару ці разблакіроўку экрана. Даведацца больш"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Выберыце, дзе <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Выберыце, дзе <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"стварыць ключы доступу"</string>
<string name="save_your_password" msgid="6597736507991704307">"захаваць пароль"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"захаваць інфармацыю пра спосаб уваходу"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Каб у далейшым хутка выконваць уваход, наладзьце стандартны менеджар пароляў для захавання вашых пароляў і ключоў доступу."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Стварыць ключ доступу ў папцы \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Захаваць пароль у папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Захаваць інфармацыю пра спосаб уваходу ў папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
<string name="password" msgid="6738570945182936667">"пароль"</string>
<string name="sign_ins" msgid="4710739369149469208">"спосабы ўваходу"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Дзе стварыць ключ доступу:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Куды захаваць пароль:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Куды захаваць спосаб уваходу:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Стварыць ключ доступу на іншай прыладзе?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Выкарыстоўваць папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\" для ўсіх спосабаў уваходу?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Каб вам было прасцей уваходзіць у сістэму, вашы паролі і ключы доступу будуць захоўвацца ў менеджары пароляў."</string>
<string name="set_as_default" msgid="4415328591568654603">"Выкарыстоўваць стандартна"</string>
<string name="use_once" msgid="9027366575315399714">"Скарыстаць адзін раз"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Пароляў: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, ключоў доступу: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Пароляў: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Ключоў доступу: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Ключ доступу"</string>
<string name="another_device" msgid="5147276802037801217">"Іншая прылада"</string>
<string name="other_password_manager" msgid="565790221427004141">"Іншыя спосабы ўваходу"</string>
<string name="close_sheet" msgid="1393792015338908262">"Закрыць аркуш"</string>
diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml
index af7eb172810a..302cc3a010bb 100644
--- a/packages/CredentialManager/res/values-bg/strings.xml
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Мениджър на идентификационни данни"</string>
<string name="string_cancel" msgid="6369133483981306063">"Отказ"</string>
<string name="string_continue" msgid="1346732695941131882">"Напред"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Създаване другаде"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Запазване на друго място"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Използване на друго устройство"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Запазване на друго устройство"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Лесен начин за безопасно влизане в профил"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Използвайте отпечатъка, лицето или опцията си за заключване на екрана, за да влизате в профила си с помощта на уникален код за достъп, който не може да бъде забравен или откраднат. Научете повече"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Изберете място за <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Изберете място за <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"създаване на кодовете ви за достъп"</string>
<string name="save_your_password" msgid="6597736507991704307">"запазване на паролата ви"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"запазване на данните ви за вход"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Задайте основен мениджър на пароли, за да запазвате своите пароли и кодове за достъп, така че следващия път да влезете по-бързо в профила си."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Да се създаде ли код за достъп в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Искате ли да запазите паролата си в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Искате ли да запазите данните си за вход в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"код за достъп"</string>
<string name="password" msgid="6738570945182936667">"парола"</string>
<string name="sign_ins" msgid="4710739369149469208">"данни за вход"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Създаване на код за достъп в(ъв)"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Запазване на паролата в(ъв)"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Запазване на данните за вход в(ъв)"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Да се създаде ли код за достъп на друго устройство?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Да се използва ли <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> за всичките ви данни за вход?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Този мениджър на пароли ще съхранява вашите пароли и кодове за достъп, за да влизате лесно в профила си."</string>
<string name="set_as_default" msgid="4415328591568654603">"Задаване като основно"</string>
<string name="use_once" msgid="9027366575315399714">"Еднократно използване"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> пароли, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> кода за достъп"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> пароли"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> кода за достъп"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Код за достъп"</string>
<string name="another_device" msgid="5147276802037801217">"Друго устройство"</string>
<string name="other_password_manager" msgid="565790221427004141">"Други мениджъри на пароли"</string>
<string name="close_sheet" msgid="1393792015338908262">"Затваряне на таблицата"</string>
diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml
index 152e5bd8e852..ad0bdeac8b7e 100644
--- a/packages/CredentialManager/res/values-bn/strings.xml
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"CredentialManager"</string>
<string name="string_cancel" msgid="6369133483981306063">"বাতিল করুন"</string>
<string name="string_continue" msgid="1346732695941131882">"চালিয়ে যান"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"অন্য জায়গায় তৈরি করুন"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"অন্য জায়গায় সেভ করুন"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"অন্য ডিভাইস ব্যবহার করুন"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"অন্য ডিভাইসে সেভ করুন"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"নিরাপদে সাইন-ইন করার একটি সহজ উপায়"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"একটি অনন্য পাসকী ব্যবহার করে সাইন-ইন করতে আপনার ফিঙ্গারপ্রিন্ট, মুখ বা স্ক্রিন লক ব্যবহার করুন যেটি ভুলে যাবেন না বা হারিয়ে যাবেন না। আরও জানুন"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> কোথায় সেভ করবেন তা বেছে নিন"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> কোথায় সেভ করবেন তা বেছে নিন"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"আপনার পাসকী তৈরি করা"</string>
<string name="save_your_password" msgid="6597736507991704307">"আপনার পাসওয়ার্ড সেভ করুন"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"আপনার সাইন-ইন করা সম্পর্কিত তথ্য সেভ করুন"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"আপনার পাসওয়ার্ড ও পাসকী সেভ করার জন্য একটি ডিফল্ট Password Manager সেট করুন এবং পরবর্তী সময়ে আরও ঝটপট সাইন-ইন করুন।"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-এ পাসকী তৈরি করবেন?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"আপনার পাসওয়ার্ড <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-এ সেভ করবেন?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"আপনার সাইন-ইন করা সম্পর্কিত তথ্য <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-এ সেভ করবেন?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"পাসকী"</string>
<string name="password" msgid="6738570945182936667">"পাসওয়ার্ড"</string>
<string name="sign_ins" msgid="4710739369149469208">"সাইন-ইন"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"এখানে পাসকী তৈরি করুন"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"এখানে পাসওয়ার্ড সেভ করা"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"এখানে সাইন-ইন করা সম্পর্কিত ক্রেডেনশিয়াল সেভ করা"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"অন্য একটি ডিভাইসে পাসকী তৈরি করবেন?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"আপনার সব সাইন-ইনের জন্য <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ব্যবহার করবেন?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"এই Password Manager আপনার পাসওয়ার্ড ও পাসকী সেভ করবে, যাতে সহজেই সাইন-ইন করতে পারেন।"</string>
<string name="set_as_default" msgid="4415328591568654603">"ডিফল্ট হিসেবে সেট করুন"</string>
<string name="use_once" msgid="9027366575315399714">"একবার ব্যবহার করুন"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>টি পাসওয়ার্ড, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>টি পাসকী"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>টি পাসওয়ার্ড"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>টি পাসকী"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"পাসকী"</string>
<string name="another_device" msgid="5147276802037801217">"অন্য ডিভাইস"</string>
<string name="other_password_manager" msgid="565790221427004141">"অন্যান্য Password Manager"</string>
<string name="close_sheet" msgid="1393792015338908262">"শিট বন্ধ করুন"</string>
diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
index d774b8810f21..2a96102c65bf 100644
--- a/packages/CredentialManager/res/values-bs/strings.xml
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Sačuvajte na drugom mjestu"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Koristite drugi uređaj"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Sačuvajte na drugom uređaju"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednostavan način za sigurnu prijavu"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Koristite otisak prsta, lice ili zaključavanje ekrana da se prijavite jedinstvenim pristupnim ključem koji se ne može zaboraviti niti ukrasti. Saznajte više"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite gdje <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite gdje <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"izradite pristupne ključeve"</string>
<string name="save_your_password" msgid="6597736507991704307">"sačuvajte lozinku"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"sačuvajte informacije za prijavu"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Postavite zadani upravitelj zaporki da biste spremili zaporke i pristupne ključeve i sljedeći put se brže prijavili."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Kreirati pristupni ključ na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Sačuvati lozinku na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Sačuvati informacije za prijavu na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
<string name="password" msgid="6738570945182936667">"lozinka"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Izradite pristupni ključ u"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Spremite zaporku na"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Spremite podatke za prijavu na"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Želite li izraditi pristupni ključ na nekom drugom uređaju?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Koristiti uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> za sve vaše prijave?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Upravitelj zaporki pohranit će vaše zaporke i pristupne ključeve radi jednostavnije prijave."</string>
<string name="set_as_default" msgid="4415328591568654603">"Postavi kao zadano"</string>
<string name="use_once" msgid="9027366575315399714">"Koristi jednom"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Broj lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>; broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
index bfd91647bd9c..8b1e395280c4 100644
--- a/packages/CredentialManager/res/values-ca/strings.xml
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Gestor de credencials"</string>
<string name="string_cancel" msgid="6369133483981306063">"Cancel·la"</string>
<string name="string_continue" msgid="1346732695941131882">"Continua"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Crea en un altre lloc"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Desa en un altre lloc"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Utilitza un altre dispositiu"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Desa en un altre dispositiu"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Una manera senzilla i segura d\'iniciar la sessió"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Utilitza l\'empremta digital, la cara o el bloqueig de pantalla per iniciar la sessió amb una clau d\'accés única que no es pot oblidar ni robar. Més informació"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Tria on vols <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Tria on vols <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"crea les teves claus d\'accés"</string>
<string name="save_your_password" msgid="6597736507991704307">"desar la contrasenya"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"desar la teva informació d\'inici de sessió"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Defineix un gestor de contrasenyes predeterminat per desar les teves contrasenyes i claus d\'accés d\'una manera més ràpida la pròxima vegada."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vols crear una clau d\'accés a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Vols desar la contrasenya a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vols desar la teva informació d\'inici de sessió a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"clau d\'accés"</string>
<string name="password" msgid="6738570945182936667">"contrasenya"</string>
<string name="sign_ins" msgid="4710739369149469208">"inicis de sessió"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Crea una clau d\'accés a"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Desa la contrasenya a"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Desa l\'inici de sessió a"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vols crear una clau d\'accés en un altre dispositiu?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vols utilitzar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> per a tots els teus inicis de sessió?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Aquest gestor de contrasenyes emmagatzemarà les teves contrasenyes i claus d\'accés per ajudar-te a iniciar la sessió fàcilment."</string>
<string name="set_as_default" msgid="4415328591568654603">"Estableix com a predeterminada"</string>
<string name="use_once" msgid="9027366575315399714">"Utilitza un cop"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasenyes, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> claus d\'accés"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasenyes"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> claus d\'accés"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Clau d\'accés"</string>
<string name="another_device" msgid="5147276802037801217">"Un altre dispositiu"</string>
<string name="other_password_manager" msgid="565790221427004141">"Altres gestors de contrasenyes"</string>
<string name="close_sheet" msgid="1393792015338908262">"Tanca el full"</string>
diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml
index 72a5f98e9ad4..b03203304d6d 100644
--- a/packages/CredentialManager/res/values-cs/strings.xml
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Správce oprávnění"</string>
<string name="string_cancel" msgid="6369133483981306063">"Zrušit"</string>
<string name="string_continue" msgid="1346732695941131882">"Pokračovat"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Vytvořit na jiném místě"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Uložit na jiné místo"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Použít jiné zařízení"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Uložit do jiného zařízení"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednoduchý způsob, jak se bezpečně přihlásit"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Použijte svůj otisk prstu, obličej nebo zámek obrazovky k přihlášení pomocí jedinečného přístupového klíče, který nemůžete zapomenout a který vám nikdo nemůže odcizit. Další informace"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Zvolte, kde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Zvolte, kde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"vytvářet přístupové klíče"</string>
<string name="save_your_password" msgid="6597736507991704307">"uložte si heslo"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"uložte své přihlašovací údaje"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Nastavte si výchozího správce hesel, do kterého si budete ukládat hesla a přístupové klíče za účelem rychlejšího přihlašování."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vytvořit přístupový klíč v <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Uložit heslo do <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Uložit přihlašovací údaje do <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"přístupový klíč"</string>
<string name="password" msgid="6738570945182936667">"heslo"</string>
<string name="sign_ins" msgid="4710739369149469208">"přihlášení"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Vytvořit přístupový klíč v"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Uložit heslo do účtu"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Uložit přihlášení do"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vytvořit přístupový klíč v jiném zařízení?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Používat <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pro všechna přihlášení?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Tento správce hesel bude ukládat vaše hesla a přístupové klíče, abyste se mohli snadno přihlásit."</string>
<string name="set_as_default" msgid="4415328591568654603">"Nastavit jako výchozí"</string>
<string name="use_once" msgid="9027366575315399714">"Použít jednou"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Počet hesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, počet přístupových klíčů: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Počet hesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Počet přístupových klíčů: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Přístupový klíč"</string>
<string name="another_device" msgid="5147276802037801217">"Jiné zařízení"</string>
<string name="other_password_manager" msgid="565790221427004141">"Další správci hesel"</string>
<string name="close_sheet" msgid="1393792015338908262">"Zavřít list"</string>
diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml
index a05137e1401f..0c63af5273dc 100644
--- a/packages/CredentialManager/res/values-da/strings.xml
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Loginstyring"</string>
<string name="string_cancel" msgid="6369133483981306063">"Annuller"</string>
<string name="string_continue" msgid="1346732695941131882">"Fortsæt"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Opret et andet sted"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Gem et andet sted"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Brug en anden enhed"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Gem på en anden enhed"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"En nemmere og mere sikker måde at logge ind på"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Brug dit fingeraftryk, dit ansigt eller din skærmlås for at logge ind med en unik adgangsnøgle, der hverken kan glemmes eller stjæles. Få flere oplysninger"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Vælg, hvor du vil <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Vælg, hvor du vil <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"oprette dine adgangsnøgler"</string>
<string name="save_your_password" msgid="6597736507991704307">"gem din adgangskode"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"gem dine loginoplysninger"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Angiv en standardadgangskodeadministrator for at gemme dine adgangskoder og adgangsnøgler og logge hurtigere ind næste gang."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vil du oprette en adgangsnøgle i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Vil du gemme din adgangskode i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vil du gemme dine loginoplysninger i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"adgangsnøgle"</string>
<string name="password" msgid="6738570945182936667">"adgangskode"</string>
<string name="sign_ins" msgid="4710739369149469208">"loginmetoder"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Opret adgangsnøgle i"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Gem adgangskode i"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Gem loginmetode i"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vil du oprette en adgangsnøgle i en anden enhed?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vil du bruge <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> til alle dine loginmetoder?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Denne adgangskodeadministrator gemmer dine adgangskoder og adgangsnøgler for at hjælpe dig med nemt at logge ind."</string>
<string name="set_as_default" msgid="4415328591568654603">"Angiv som standard"</string>
<string name="use_once" msgid="9027366575315399714">"Brug én gang"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> adgangskoder, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> adgangsnøgler"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> adgangskoder"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> adgangsnøgler"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Adgangsnøgle"</string>
<string name="another_device" msgid="5147276802037801217">"En anden enhed"</string>
<string name="other_password_manager" msgid="565790221427004141">"Andre adgangskodeadministratorer"</string>
<string name="close_sheet" msgid="1393792015338908262">"Luk arket"</string>
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
index fa1e8f10f87a..7d50aed3056f 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"An anderem Ort speichern"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Anderes Gerät verwenden"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Auf einem anderen Gerät speichern"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Einfach und sicher anmelden"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Verwende deinen Fingerabdruck oder deine Gesichts- bzw. Displaysperre, um dich mit einem eindeutigen Passkey anzumelden, der nicht vergessen oder gestohlen werden kann. Weitere Informationen"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Ort auswählen für: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Ort auswählen für: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"Passkeys erstellen"</string>
<string name="save_your_password" msgid="6597736507991704307">"Passwort speichern"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"Anmeldedaten speichern"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Du kannst einen Passwortmanager festlegen, der standardmäßig zum Speichern deiner Passwörter und Passkeys verwendet wird, damit du dich das nächste Mal schneller anmelden kannst."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Passkey hier erstellen: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Passwort hier speichern: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Anmeldedaten hier speichern: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"Passkey"</string>
<string name="password" msgid="6738570945182936667">"Passwort"</string>
<string name="sign_ins" msgid="4710739369149469208">"Anmeldungen"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Passkey hier erstellen:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Passwort hier speichern:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Anmeldedaten hier speichern:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Passkey auf anderem Gerät erstellen?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> für alle Anmeldungen verwenden?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Mit diesem Passwortmanager werden deine Passwörter und Passkeys gespeichert, damit du dich problemlos anmelden kannst."</string>
<string name="set_as_default" msgid="4415328591568654603">"Als Standard festlegen"</string>
<string name="use_once" msgid="9027366575315399714">"Einmal verwenden"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> Passwörter, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> Passkeys"</string>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index 706d9f3c4c7a..a088d1deb3d0 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Αποθήκευση σε άλλη θέση"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Χρήση άλλης συσκευής"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Αποθήκευση σε άλλη συσκευή"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Ένας απλός τρόπος για ασφαλή σύνδεση"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Χρησιμοποιήστε το δακτυλικό αποτύπωμα, το πρόσωπο ή το κλείδωμα οθόνης σας για να συνδεθείτε με ένα μοναδικό κλειδί πρόσβασης που δεν είναι δυνατό να ξεχάσετε ή να κλαπεί. Μάθετε περισσότερα"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Επιλέξτε θέση για <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Επιλέξτε θέση για <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"δημιουργήστε τα κλειδιά πρόσβασής σας"</string>
<string name="save_your_password" msgid="6597736507991704307">"αποθήκευση του κωδικού πρόσβασής σας"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"αποθήκευση των στοιχείων σύνδεσής σας"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Για να συνδέεστε πιο γρήγορα, ορίστε ένα προεπιλεγμένο πρόγραμμα διαχείρισης κωδικών πρόσβασης για να αποθηκεύετε τους κωδικούς και τα κλειδιά πρόσβασής σας."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Να δημιουργηθει κλειδί πρόσβασης στο <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>;"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Να αποθηκευτεί ο κωδικός πρόσβασής σας στο <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>;"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Να αποθηκευτούν τα στοιχεία σύνδεσής σας στο <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>;"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"κλειδί πρόσβασης"</string>
<string name="password" msgid="6738570945182936667">"κωδικός πρόσβασης"</string>
<string name="sign_ins" msgid="4710739369149469208">"στοιχεία σύνδεσης"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Δημιουργία κλειδιού πρόσβασης σε"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Αποθήκευση κωδικού πρόσβασης σε"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Αποθήκευση στοιχείων σύνδεσης σε"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Δημιουργία κλειδιού πρόσβασης σε άλλη συσκευή;"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Να χρησιμοποιηθεί το <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> για όλες τις συνδέσεις σας;"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Αυτός ο διαχειριστής κωδικών πρόσβασης θα αποθηκεύει τους κωδικούς πρόσβασης και τα κλειδιά πρόσβασης, για να συνδέεστε εύκολα."</string>
<string name="set_as_default" msgid="4415328591568654603">"Ορισμός ως προεπιλογής"</string>
<string name="use_once" msgid="9027366575315399714">"Χρήση μία φορά"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> κωδικοί πρόσβασης, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> κλειδιά πρόσβασης"</string>
diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
index 7adeded11424..a9a6f02909b2 100644
--- a/packages/CredentialManager/res/values-en-rAU/strings.xml
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -8,8 +8,14 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
<string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
<string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
index 8a8b8845f4cf..c895a41ce132 100644
--- a/packages/CredentialManager/res/values-en-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -8,8 +8,10 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Safer with passkeys"</string>
+ <string name="passkey_creation_intro_body_password" msgid="312712407571126228">"No need to create or remember complex passwords"</string>
+ <string name="passkey_creation_intro_body_fingerprint" msgid="691816235541508203">"Use your fingerprint, face, or screen lock to create a unique passkey"</string>
+ <string name="passkey_creation_intro_body_device" msgid="477121861162321129">"Passkeys are saved to a password manager, so you can sign in on other devices"</string>
<string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
<string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
index 7adeded11424..a9a6f02909b2 100644
--- a/packages/CredentialManager/res/values-en-rGB/strings.xml
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -8,8 +8,14 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
<string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
<string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
index 7adeded11424..a9a6f02909b2 100644
--- a/packages/CredentialManager/res/values-en-rIN/strings.xml
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -8,8 +8,14 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
<string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
<string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
index 85e94dfb60a8..efa0633c6cf9 100644
--- a/packages/CredentialManager/res/values-en-rXC/strings.xml
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -8,8 +8,10 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‎Save to another place‎‏‎‎‏‎"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎Use another device‎‏‎‎‏‎"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎Save to another device‎‏‎‎‏‎"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎A simple way to sign in safely‎‏‎‎‏‎"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more‎‏‎‎‏‎"</string>
+ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎Safer with passkeys‎‏‎‎‏‎"</string>
+ <string name="passkey_creation_intro_body_password" msgid="312712407571126228">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎No need to create or remember complex passwords‎‏‎‎‏‎"</string>
+ <string name="passkey_creation_intro_body_fingerprint" msgid="691816235541508203">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎Use your fingerprint, face, or screen lock to create a unique passkey‎‏‎‎‏‎"</string>
+ <string name="passkey_creation_intro_body_device" msgid="477121861162321129">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‎‏‎Passkeys are saved to a password manager, so you can sign in on other devices‎‏‎‎‏‎"</string>
<string name="choose_provider_title" msgid="7245243990139698508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎Choose where to ‎‏‎‎‏‏‎<xliff:g id="CREATETYPES">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="create_your_passkeys" msgid="8901224153607590596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‎‎‏‎‎‎create your passkeys‎‏‎‎‏‎"</string>
<string name="save_your_password" msgid="6597736507991704307">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎save your password‎‏‎‎‏‎"</string>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
index 5b8e4429ed94..21f072014a31 100644
--- a/packages/CredentialManager/res/values-es-rUS/strings.xml
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar en otra ubicación"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Usar otro dispositivo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar en otro dispositivo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un modo simple y seguro de ingresar"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa tu huella dactilar, tu rostro o el bloqueo de pantalla para acceder con una llave de acceso única que no olvidarás ni podrán robarte. Más información"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"crea tus llaves de acceso"</string>
<string name="save_your_password" msgid="6597736507991704307">"guardar tu contraseña"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar tu información de acceso"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Configura un administrador de contraseñas predeterminado para guardar tus contraseñas y llaves de acceso, y acceder más rápido la próxima vez."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"¿Quieres crear una llave de acceso en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"¿Quieres guardar tu contraseña de <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"¿Quieres guardar tu información de acceso a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contraseña"</string>
<string name="sign_ins" msgid="4710739369149469208">"accesos"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Crear llave de acceso en"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Guardar contraseña en"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Guardar acceso en"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"¿Quieres crear una llave de acceso en otro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"¿Quieres usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos tus accesos?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este administrador de contraseñas almacenará tus contraseñas y llaves de acceso para ayudarte a acceder fácilmente."</string>
<string name="set_as_default" msgid="4415328591568654603">"Establecer como predeterminado"</string>
<string name="use_once" msgid="9027366575315399714">"Usar una vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> llaves de acceso, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> contraseñas"</string>
diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml
index 19fde728ac0e..409bdacae966 100644
--- a/packages/CredentialManager/res/values-es/strings.xml
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Gestor de credenciales"</string>
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Crear en otro lugar"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar en otro lugar"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Usar otro dispositivo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar en otro dispositivo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Una forma sencilla y segura de iniciar sesión"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa la huella digital, la cara o el bloqueo de pantalla para iniciar sesión con una llave de acceso única que no se puede olvidar ni robar. Más información"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"crea tus llaves de acceso"</string>
<string name="save_your_password" msgid="6597736507991704307">"guardar tu contraseña"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar tu información de inicio de sesión"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Define un gestor de contraseñas predeterminado para guardar tus contraseñas y llaves de acceso e iniciar sesión más rápido la próxima vez."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"¿Crear una llave de acceso en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"¿Guardar tu contraseña en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"¿Guardar tu información de inicio de sesión en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contraseña"</string>
<string name="sign_ins" msgid="4710739369149469208">"inicios de sesión"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Crear llave de acceso en"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Guardar contraseña en"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Guardar inicio de sesión en"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"¿Crear una llave de acceso en otro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"¿Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos tus inicios de sesión?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gestor de contraseñas almacenará tus contraseñas y llaves de acceso para que puedas iniciar sesión fácilmente."</string>
<string name="set_as_default" msgid="4415328591568654603">"Fijar como predeterminado"</string>
<string name="use_once" msgid="9027366575315399714">"Usar una vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contraseñas, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> llaves de acceso"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contraseñas"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> llaves de acceso"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Llave de acceso"</string>
<string name="another_device" msgid="5147276802037801217">"Otro dispositivo"</string>
<string name="other_password_manager" msgid="565790221427004141">"Otros gestores de contraseñas"</string>
<string name="close_sheet" msgid="1393792015338908262">"Cerrar hoja"</string>
diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml
index 5b1b0705c053..bfaec7814258 100644
--- a/packages/CredentialManager/res/values-et/strings.xml
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Mandaatide haldur"</string>
<string name="string_cancel" msgid="6369133483981306063">"Tühista"</string>
<string name="string_continue" msgid="1346732695941131882">"Jätka"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Loo teises kohas"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Salvesta teise kohta"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Kasuta teist seadet"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Salvesta teise seadmesse"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Lihtne viis turvaliselt sisselogimiseks"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Kasutage sõrmejälge, nägu või ekraanilukku, et logida sisse unikaalse pääsuvõtmega, mida ei saa unustada ega varastada. Lisateave"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Valige, kus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Valige, kus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"looge oma pääsuvõtmed"</string>
<string name="save_your_password" msgid="6597736507991704307">"parool salvestada"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"sisselogimisandmed salvestada"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Määrake vaikeparoolihaldur, et oma paroolid ja pääsuvõtmed salvestada ning järgmisel korral kiiremini sisse logida."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Kas luua teenuses <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pääsuvõti?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Kas salvestada parool teenusesse <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Kas salvestada sisselogimisteave teenusesse <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"pääsukood"</string>
<string name="password" msgid="6738570945182936667">"parool"</string>
<string name="sign_ins" msgid="4710739369149469208">"sisselogimisandmed"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Loo pääsuvõti:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Salvesta parool:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Salvesta sisselogimisandmed:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Kas luua pääsuvõti teises seadmes?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Kas kasutada teenust <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kõigi teie sisselogimisandmete puhul?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"See paroolihaldur salvestab teie paroolid ja pääsuvõtmed, et aidata teil hõlpsalt sisse logida."</string>
<string name="set_as_default" msgid="4415328591568654603">"Määra vaikeseadeks"</string>
<string name="use_once" msgid="9027366575315399714">"Kasuta ühe korra"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parooli, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> pääsuvõtit"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parooli"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> pääsuvõtit"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Pääsukood"</string>
<string name="another_device" msgid="5147276802037801217">"Teine seade"</string>
<string name="other_password_manager" msgid="565790221427004141">"Muud paroolihaldurid"</string>
<string name="close_sheet" msgid="1393792015338908262">"Sule leht"</string>
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
index b2c1fe5252dd..5a1494b52247 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Kredentzialen kudeatzailea"</string>
<string name="string_cancel" msgid="6369133483981306063">"Utzi"</string>
<string name="string_continue" msgid="1346732695941131882">"Egin aurrera"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Sortu beste toki batean"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Gorde beste toki batean"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Erabili beste gailu bat"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Gorde beste gailu batean"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Segurtasun osoz saioa hasteko modu erraza"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Erabili hatz-marka, aurpegia edo pantailaren blokeoa ahaztu edo lapurtu ezin den sarbide-gako baten bidez saioa hasteko. Lortu informazio gehiago"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Aukeratu non <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Aukeratu non <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"sortu sarbide-gakoak"</string>
<string name="save_your_password" msgid="6597736507991704307">"gorde pasahitza"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"gorde kredentzialei buruzko informazioa"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Ezarri pasahitz-kudeatzaile lehenetsia pasahitzak eta sarbide-gakoak gordetzeko, eta hurrengoan saioa bizkorrago hasteko."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Sarbide-gako bat sortu nahi duzu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> aplikazioan?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Pasahitza <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> aplikazioan gorde nahi duzu?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Kredentzialei buruzko informazioa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> aplikazioan gorde nahi duzu?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"sarbide-gakoa"</string>
<string name="password" msgid="6738570945182936667">"pasahitza"</string>
<string name="sign_ins" msgid="4710739369149469208">"kredentzialak"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Sortu sarbide-gako bat hemen:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Gorde pasahitza hemen:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Gorde kredentzialak hemen:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Sarbide-gako bat sortu nahi duzu beste gailu batean?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> erabili nahi duzu kredentzial guztietarako?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Pasahitz-kudeatzaile honek pasahitzak eta sarbide-gakoak gordeko ditu saioa erraz has dezazun."</string>
<string name="set_as_default" msgid="4415328591568654603">"Ezarri lehenetsi gisa"</string>
<string name="use_once" msgid="9027366575315399714">"Erabili behin"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> pasahitz eta <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> sarbide-gako"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> pasahitz"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> sarbide-gako"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Sarbide-gakoa"</string>
<string name="another_device" msgid="5147276802037801217">"Beste gailu bat"</string>
<string name="other_password_manager" msgid="565790221427004141">"Beste pasahitz-kudeatzaile batzuk"</string>
<string name="close_sheet" msgid="1393792015338908262">"Itxi orria"</string>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
index 98b487caf026..065bde4825b0 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"مدیر اعتبارنامه"</string>
<string name="string_cancel" msgid="6369133483981306063">"لغو"</string>
<string name="string_continue" msgid="1346732695941131882">"ادامه"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"ایجاد در مکانی دیگر"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"ذخیره در مکانی دیگر"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"استفاده از دستگاهی دیگر"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"ذخیره در دستگاهی دیگر"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"روشی ساده برای ورود به سیستم ایمن"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"برای ورود به سیستم با گذرکلیدی یکتا که غیرقابل فراموش شدن یا دزدیده شدن باشد، از اثر انگشت، چهره، یا قفل صفحه استفاده کنید. بیشتر بدانید"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"انتخاب محل <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"انتخاب محل <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ایجاد گذرکلید"</string>
<string name="save_your_password" msgid="6597736507991704307">"ذخیره گذرواژه"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ذخیره اطلاعات ورود به سیستم"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"برای ذخیره کردن گذرواژه‌ها و گذرکلیدهایتان، مدیر گذرواژه پیش‌فرض تنظیم کنید تا دفعه بعدی سریع‌تر به سیستم وارد شوید."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"گذرکلید در <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ایجاد شود؟"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"گذرواژه در <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ذخیره شود؟"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"اطلاعات ورود به سیستم در <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ذخیره شود؟"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"گذرکلید"</string>
<string name="password" msgid="6738570945182936667">"گذرواژه"</string>
<string name="sign_ins" msgid="4710739369149469208">"ورود به سیستم‌ها"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ایجاد گذرکلید در"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"ذخیره گذرواژه در"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ذخیره ورود به سیستم در"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"گذرکلید در دستگاهی دیگر ایجاد شود؟"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"از <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> برای همه ورود به سیستم‌ها استفاده شود؟"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"این مدیر گذرواژه گذرکلیدها و گذرواژه‌های شما را ذخیره خواهد کرد تا به‌راحتی بتوانید به سیستم وارد شوید."</string>
<string name="set_as_default" msgid="4415328591568654603">"تنظیم به‌عنوان پیش‌فرض"</string>
<string name="use_once" msgid="9027366575315399714">"یک‌بار استفاده"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> گذرواژه، <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> گذرکلید"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> گذرواژه"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> گذرکلید"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"گذرکلید"</string>
<string name="another_device" msgid="5147276802037801217">"دستگاهی دیگر"</string>
<string name="other_password_manager" msgid="565790221427004141">"دیگر مدیران گذرواژه"</string>
<string name="close_sheet" msgid="1393792015338908262">"بستن برگ"</string>
diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml
index 9ad178a456bf..cbea24bea2b6 100644
--- a/packages/CredentialManager/res/values-fi/strings.xml
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Kirjautumistietojen hallinta"</string>
<string name="string_cancel" msgid="6369133483981306063">"Peru"</string>
<string name="string_continue" msgid="1346732695941131882">"Jatka"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Luo muualla"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Tallenna muualle"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Käytä toista laitetta"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Tallenna toiselle laitteelle"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Helppo tapa kirjautua turvallisesti sisään"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Käytä sormenjälkeä, kasvoja tai näytön lukitusta, niin voit kirjautua sisään yksilöllisellä avainkoodilla, jota ei voi unohtaa tai varastaa. Lue lisää"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Valitse paikka: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Valitse paikka: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"luo avainkoodeja"</string>
<string name="save_your_password" msgid="6597736507991704307">"tallenna salasanasi"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"tallenna kirjautumistiedot"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Aseta salasanojen ylläpidolle oletustyökalu, niin voit tallentaa salasanat ja avainkoodit sekä kirjautua sisään nopeammin ensi kerralla."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Luodaanko avainkoodi (<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>)?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Tallennetaanko salasanasi tänne: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Tallennetaanko kirjautumistietosi tänne: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"avainkoodi"</string>
<string name="password" msgid="6738570945182936667">"salasana"</string>
<string name="sign_ins" msgid="4710739369149469208">"sisäänkirjautumiset"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Luo avainkoodi tänne:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Tallenna salasana tänne:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Tallenna kirjautumistiedot tänne:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Luodaanko avainkoodi toisella laitteella?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Otetaanko <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> käyttöön kaikissa sisäänkirjautumisissa?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Tämä salasanojen ylläpitotyökalu tallentaa salasanat ja avainkoodit, jotta voit kirjautua helposti sisään."</string>
<string name="set_as_default" msgid="4415328591568654603">"Aseta oletukseksi"</string>
<string name="use_once" msgid="9027366575315399714">"Käytä kerran"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> salasanaa, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> avainkoodia"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> salasanaa"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> avainkoodia"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Avainkoodi"</string>
<string name="another_device" msgid="5147276802037801217">"Toinen laite"</string>
<string name="other_password_manager" msgid="565790221427004141">"Muut salasanojen ylläpitotyökalut"</string>
<string name="close_sheet" msgid="1393792015338908262">"Sulje taulukko"</string>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index a2e758173770..b122fd24b00f 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Enregistrer à un autre emplacement"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Utiliser un autre appareil"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Enregistrer sur un autre appareil"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Une manière simple de se connecter en toute sécurité"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Utilisez vos empreintes digitales, votre visage ou un écran de verrouillage pour vous connecter avec une clé d\'accès unique qui ne peut pas être oubliée ou volée. En savoir plus"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"créer vos clés d\'accès"</string>
<string name="save_your_password" msgid="6597736507991704307">"enregistrer votre mot de passe"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"enregistrer vos données de connexion"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Sélectionnez un gestionnaire de mots de passe par défaut où seront enregistrés vos mots de passe et vos clés d\'accès, et connectez-vous plus rapidement la prochaine fois."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Créer une clé d\'accès dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Enregistrer votre mot de passe dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Enregistrer vos données de connexion dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
<string name="password" msgid="6738570945182936667">"mot de passe"</string>
<string name="sign_ins" msgid="4710739369149469208">"connexions"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Créer une clé d\'accès dans"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Enregistrer le mot de passe dans"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Enregistrer la connexion dans"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Créer une clé d\'accès dans un autre appareil?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ce gestionnaire de mots de passe va enregistrer vos mots de passe et vos clés d\'accès pour vous aider à vous connecter facilement."</string>
<string name="set_as_default" msgid="4415328591568654603">"Définir par défaut"</string>
<string name="use_once" msgid="9027366575315399714">"Utiliser une fois"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clés d\'accès"</string>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
index 2b280fb7a2a1..cf69329e6bec 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Enregistrer ailleurs"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Utiliser un autre appareil"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Enregistrer sur un autre appareil"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Une façon simple et sécurisée de vous connecter"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Utilisez votre empreinte digitale, votre visage ou le verrouillage de l\'écran pour vous connecter avec une clé d\'accès unique que vous ne pourrez pas oublier ni vous faire voler. En savoir plus"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"créer vos clés d\'accès"</string>
<string name="save_your_password" msgid="6597736507991704307">"enregistrer votre mot de passe"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"enregistrer vos informations de connexion"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Définissez un gestionnaire de mots de passe par défaut pour enregistrer vos mots de passe et clés d\'accès et vous connecter plus rapidement la prochaine fois."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Créer une clé d\'accès dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Enregistrer votre mot de passe dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Enregistrer vos informations de connexion dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
<string name="password" msgid="6738570945182936667">"mot de passe"</string>
<string name="sign_ins" msgid="4710739369149469208">"connexions"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Créer une clé d\'accès dans"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Enregistrer le mot de passe dans"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Enregistrer les informations de connexion dans"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Créer une clé d\'accès dans un autre appareil ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ce gestionnaire de mots de passe stockera vos mots de passe et clés d\'accès pour vous permettre de vous connecter facilement."</string>
<string name="set_as_default" msgid="4415328591568654603">"Définir par défaut"</string>
<string name="use_once" msgid="9027366575315399714">"Utiliser une fois"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clés d\'accès"</string>
diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml
index cc03ca4ac3a0..c41dca0fbb27 100644
--- a/packages/CredentialManager/res/values-gl/strings.xml
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Gardar noutro lugar"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Gardar noutro dispositivo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un xeito fácil de iniciar sesión de forma segura"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa a impresión dixital, a cara ou o bloqueo de pantalla para iniciar sesión cunha clave de acceso única que non podes esquecer nin cha poden roubar. Máis información"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Escolle onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Escolle onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"crear as túas claves de acceso"</string>
<string name="save_your_password" msgid="6597736507991704307">"gardar o contrasinal"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"gardar a información de inicio de sesión"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Configura un xestor de contrasinais como predefinido para gardar os teus contrasinais e as túas claves de acceso, e iniciar sesión máis rápido a próxima vez."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Queres crear unha clave de acceso en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Queres gardar o contrasinal en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Queres gardar a información de inicio de sesión en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"clave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contrasinal"</string>
<string name="sign_ins" msgid="4710739369149469208">"métodos de inicio de sesión"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Crear clave de acceso en"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Gardar contrasinal en"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Gardar método de inicio de sesión en"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Queres crear unha clave de acceso noutro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Queres usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> cada vez que inicies sesión?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este xestor de contrasinais almacenará os contrasinais e as claves de acceso para axudarche a iniciar sesión facilmente."</string>
<string name="set_as_default" msgid="4415328591568654603">"Establecer como predeterminado"</string>
<string name="use_once" msgid="9027366575315399714">"Usar unha vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasinais, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> claves de acceso"</string>
diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml
index f796d207823e..17df19ef95fc 100644
--- a/packages/CredentialManager/res/values-gu/strings.xml
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"કોઈ અન્ય સ્થાન પર સાચવો"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"અન્ય ડિવાઇસ પર સાચવો"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"સલામત રીતે સાઇન ઇન કરવાની સરળ રીત"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ભૂલી ન શકાય કે ચોરાઈ ન જાય, તેવી કોઈ વિશિષ્ટ પાસકી વડે સાઇન ઇન કરવા માટે, તમારી ફિંગરપ્રિન્ટ, ચહેરો અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો. વધુ જાણો"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ક્યાં સાચવવી છે, તે પસંદ કરો"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ક્યાં સાચવવી છે, તે પસંદ કરો"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"તમારી પાસકી બનાવો"</string>
<string name="save_your_password" msgid="6597736507991704307">"તમારો પાસવર્ડ સાચવો"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"તમારી સાઇન-ઇનની માહિતી સાચવો"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"તમારા પાસવર્ડ અને પાસકી સાચવવા માટે કોઈ ડિફૉલ્ટ પાસવર્ડ મેનેજર સેટ કરો અને આગલી વખતે વધુ ઝડપથી સાઇન ઇન કરો."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"શું <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>માં કોઈ પાસકી બનાવીએ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"શું તમારો પાસવર્ડ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>માં સાચવીએ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"શું તમારી સાઇન-ઇનની માહિતી <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>માં સાચવીએ?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"પાસકી"</string>
<string name="password" msgid="6738570945182936667">"પાસવર્ડ"</string>
<string name="sign_ins" msgid="4710739369149469208">"સાઇન-ઇન"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"આમાં પાસકી બનાવો"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"પાસવર્ડ અહીં સાચવો"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"સાઇન-ઇનની માહિતી અહીં સાચવો"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"શું અન્ય ડિવાઇસમાં પાસકી બનાવવા માગો છો?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"શું તમારા બધા સાઇન-ઇન માટે <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>નો ઉપયોગ કરીએ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"આ પાસવર્ડ મેનેજર તમને સરળતાથી સાઇન ઇન કરવામાં સહાય કરવા માટે, તમારા પાસવર્ડ અને પાસકીને સ્ટોર કરશે."</string>
<string name="set_as_default" msgid="4415328591568654603">"ડિફૉલ્ટ તરીકે સેટ કરો"</string>
<string name="use_once" msgid="9027366575315399714">"એકવાર ઉપયોગ કરો"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> પાસવર્ડ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> પાસકી"</string>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
index fbf1c0214aac..014713953d33 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"CredentialManager"</string>
<string name="string_cancel" msgid="6369133483981306063">"रद्द करें"</string>
<string name="string_continue" msgid="1346732695941131882">"जारी रखें"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"दूसरी जगह पर बनाएं"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"दूसरी जगह पर सेव करें"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"दूसरे डिवाइस का इस्तेमाल करें"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"दूसरे डिवाइस पर सेव करें"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"सुरक्षित तरीके से साइन इन करने का आसान तरीका"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"साइन इन करने के लिए फ़िंगरप्रिंट, फ़ेस या स्क्रीन लॉक जैसी यूनीक पासकी का इस्तेमाल करें. इन्हें, न तो भुलाया जा सकता है न ही चुराया जा सकता है. ज़्यादा जानें"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"चुनें कि <xliff:g id="CREATETYPES">%1$s</xliff:g> कहां पर सेव करना है"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"चुनें कि <xliff:g id="CREATETYPES">%1$s</xliff:g> कहां पर सेव करना है"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"अपनी पासकी बनाएं"</string>
<string name="save_your_password" msgid="6597736507991704307">"अपना पासवर्ड सेव करें"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"साइन इन से जुड़ी अपनी जानकारी सेव करें"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"डिफ़ॉल्ट पासवर्ड मैनेजर सेट करें, ताकि आपके पासवर्ड और पासकी सेव की जा सकें और अगली बार आप तेज़ी से साइन इन कर सकें."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"क्या आपको <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> में पासकी बनानी है?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"क्या आपको अपना पासवर्ड <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> में सेव करना है?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"क्या आपको साइन इन करने से जुड़ी जानकारी <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> में सेव करनी है?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"पासकी"</string>
<string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
<string name="sign_ins" msgid="4710739369149469208">"साइन इन"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"पासकी इसमें बनाएं"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"पासवर्ड इसमें सेव करें"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"साइन इन से जुड़ी जानकारी इसमें सेव करें"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"क्या आपको किसी दूसरे डिवाइस में पासकी बनानी है?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"क्या आपको साइन इन से जुड़ी सारी जानकारी सेव करने के लिए, <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> का इस्तेमाल करना है?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"पासवर्ड और पासकी को इस पासवर्ड मैनेजर में सेव करके, आसानी से साइन इन किया जा सकता है."</string>
<string name="set_as_default" msgid="4415328591568654603">"डिफ़ॉल्ट के तौर पर सेट करें"</string>
<string name="use_once" msgid="9027366575315399714">"इसका इस्तेमाल एक बार किया जा सकता है"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड और <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> पासकी"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> पासकी"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"पासकी"</string>
<string name="another_device" msgid="5147276802037801217">"दूसरा डिवाइस"</string>
<string name="other_password_manager" msgid="565790221427004141">"दूसरे पासवर्ड मैनेजर"</string>
<string name="close_sheet" msgid="1393792015338908262">"शीट बंद करें"</string>
diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml
index 6c1952f38da3..a5bd3ba8269e 100644
--- a/packages/CredentialManager/res/values-hr/strings.xml
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Upravitelj vjerodajnicama"</string>
<string name="string_cancel" msgid="6369133483981306063">"Odustani"</string>
<string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Izradi na drugom mjestu"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Spremi na drugom mjestu"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Upotrijebite neki drugi uređaj"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Spremi na drugi uređaj"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednostavan način za sigurnu prijavu"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Prijavite se otiskom prsta, licem ili zaključavanjem zaslona kao jedinstvenim pristupnim ključem koji je nemoguće zaboraviti ili ukrasti. Saznajte više"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite mjesto za sljedeće: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite mjesto za sljedeće: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"izradite pristupne ključeve"</string>
<string name="save_your_password" msgid="6597736507991704307">"spremi zaporku"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"spremi podatke za prijavu"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Postavite zadani upravitelj zaporki da biste spremili zaporke i pristupne ključeve i sljedeći put se brže prijavili."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Želite li izraditi pristupni ključ na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Želite li spremiti zaporku na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Želite li spremiti podatke o prijavi na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
<string name="password" msgid="6738570945182936667">"zaporka"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Izradite pristupni ključ u"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Spremite zaporku na"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Spremite podatke za prijavu na"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Želite li izraditi pristupni ključ na nekom drugom uređaju?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite li upotrebljavati uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> za sve prijave?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Upravitelj zaporki pohranit će vaše zaporke i pristupne ključeve radi jednostavnije prijave."</string>
<string name="set_as_default" msgid="4415328591568654603">"Postavi kao zadano"</string>
<string name="use_once" msgid="9027366575315399714">"Upotrijebi jednom"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Broj zaporki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Broj zaporki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Pristupni ključ"</string>
<string name="another_device" msgid="5147276802037801217">"Drugi uređaj"</string>
<string name="other_password_manager" msgid="565790221427004141">"Drugi upravitelji zaporki"</string>
<string name="close_sheet" msgid="1393792015338908262">"Zatvaranje lista"</string>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index 0efa3e8ec537..4c7703854eeb 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Mentés másik helyre"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Másik eszköz használata"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Mentés másik eszközre"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"A biztonságos bejelentkezés egyszerű módja"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Ujjlenyomatát, arcát vagy képernyőzárát használva egyedi azonosítókulccsal jelentkezhet be, amelyet nem lehet elfelejteni vagy ellopni. További információ."</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Válassza ki a(z) <xliff:g id="CREATETYPES">%1$s</xliff:g> helyét"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Válassza ki a(z) <xliff:g id="CREATETYPES">%1$s</xliff:g> helyét"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"azonosítókulcsok létrehozása"</string>
<string name="save_your_password" msgid="6597736507991704307">"jelszó mentése"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"bejelentkezési adatok mentése"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Állítson be alapértelmezett jelszókezelőt jelszavai és azonosítókulcsai mentéséhez és a gyorsabb bejelentkezéshez."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Létrehoz azonosítókulcsot a(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> szolgáltatásban?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Menti jelszavát a(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> szolgáltatásba?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Menti bejelentkezési adatait a(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> szolgáltatásba?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"azonosítókulcs"</string>
<string name="password" msgid="6738570945182936667">"jelszó"</string>
<string name="sign_ins" msgid="4710739369149469208">"bejelentkezési adatok"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Azonosítókulcs létrehozása itt:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Jelszó mentése ide:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Bejelentkezési adatok mentése ide:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Létrehoz azonosítókulcsot egy másik eszközön?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Szeretné a következőt használni az összes bejelentkezési adatához: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ez a jelszókezelő a bejelentkezés megkönnyítése érdekében tárolja jelszavait és azonosítókulcsait."</string>
<string name="set_as_default" msgid="4415328591568654603">"Beállítás alapértelmezettként"</string>
<string name="use_once" msgid="9027366575315399714">"Egyszeri használat"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> jelszó, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> azonosítókulcs"</string>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index de47e9f5858c..afa529a6ed7d 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Մուտքի տվյալների կառավարիչ"</string>
<string name="string_cancel" msgid="6369133483981306063">"Չեղարկել"</string>
<string name="string_continue" msgid="1346732695941131882">"Շարունակել"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Ստեղծել այլ տեղում"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Պահել այլ տեղում"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Օգտագործել այլ սարք"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Պահել մեկ այլ սարքում"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Մուտք գործելու անվտանգ և պարզ եղանակ"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Օգտագործեք ձեր մատնահետքը, դեմքը կամ էկրանի կողպումը՝ մուտք գործելու հաշիվ եզակի անցաբառի միջոցով, որը հնարավոր չէ կոտրել կամ մոռանալ։ Իմանալ ավելին"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Ընտրեք, թե որտեղ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Ընտրեք, թե որտեղ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ստեղծել ձեր անցաբառերը"</string>
<string name="save_your_password" msgid="6597736507991704307">"պահել գաղտնաբառը"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"պահել մուտքի տվյալները"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Սահմանեք գաղտնաբառերի կանխադրված կառավարիչ՝ ձեր գաղտնաբառերն ու անցաբառերը պահելու և հաջորդ անգամ ավելի արագ մուտք գործելու համար։"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Ստեղծե՞լ անցաբառ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածում"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Պահե՞լ ձեր գաղտնաբառը <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածում"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Պահե՞լ ձեր մուտքի տվյալները <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածում"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"անցաբառ"</string>
<string name="password" msgid="6738570945182936667">"գաղտնաբառ"</string>
<string name="sign_ins" msgid="4710739369149469208">"մուտք"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Ստեղծել անցաբառ…"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Պահել գաղտնաբառը…"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Պահել մուտքի տվյալները…"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Ստեղծե՞լ անցաբառ մեկ այլ սարքում"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Միշտ մուտք գործե՞լ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածի միջոցով"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Գաղտնաբառերի այս կառավարիչը կպահի ձեր գաղտնաբառերն ու անցաբառերը՝ օգնելու ձեզ հեշտությամբ մուտք գործել հաշիվ։"</string>
<string name="set_as_default" msgid="4415328591568654603">"Նշել որպես կանխադրված"</string>
<string name="use_once" msgid="9027366575315399714">"Օգտագործել մեկ անգամ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> գաղտնաբառ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> անցաբառ"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> գաղտնաբառ"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> անցաբառ"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Անցաբառ"</string>
<string name="another_device" msgid="5147276802037801217">"Այլ սարք"</string>
<string name="other_password_manager" msgid="565790221427004141">"Գաղտնաբառերի այլ կառավարիչներ"</string>
<string name="close_sheet" msgid="1393792015338908262">"Փակել թերթը"</string>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
index d980d44c7f32..5cad3f39ccc1 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Simpan ke tempat lain"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Gunakan perangkat lain"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Simpan ke perangkat lain"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Cara mudah untuk login dengan aman"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gunakan sidik jari, wajah, atau kunci layar untuk login dengan kunci sandi unik yang mudah diingat dan tidak dapat dicuri. Pelajari lebih lanjut"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"membuat kunci sandi Anda"</string>
<string name="save_your_password" msgid="6597736507991704307">"menyimpan sandi Anda"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"menyimpan info login Anda"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Setel pengelola sandi default untuk menyimpan sandi dan kunci sandi sehingga nantinya Anda dapat login lebih cepat."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Buat kunci sandi di <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Simpan sandi ke <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Simpan info login ke <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"kunci sandi"</string>
<string name="password" msgid="6738570945182936667">"sandi"</string>
<string name="sign_ins" msgid="4710739369149469208">"login"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Buat kunci sandi di"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Simpan sandi ke"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Simpan info login ke"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Buat kunci sandi di perangkat lain?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua info login Anda?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Pengelola sandi ini akan menyimpan sandi dan kunci sandi untuk membantu Anda login dengan mudah."</string>
<string name="set_as_default" msgid="4415328591568654603">"Setel sebagai default"</string>
<string name="use_once" msgid="9027366575315399714">"Gunakan sekali"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> sandi, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> kunci sandi"</string>
diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml
index 3fd6af2456b9..f34dd69e7bfe 100644
--- a/packages/CredentialManager/res/values-is/strings.xml
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Skilríkjastjórnun"</string>
<string name="string_cancel" msgid="6369133483981306063">"Hætta við"</string>
<string name="string_continue" msgid="1346732695941131882">"Áfram"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Búa til annarsstaðar"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Vista annarsstaðar"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Nota annað tæki"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Vista í öðru tæki"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Einföld leið við örugga innskráningu"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Notaðu fingrafar, andlit eða skjálás til að skrá þig inn með einkvæmum aðgangslykli sem ekki er hægt að gleyma eða stela. Nánar"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Veldu hvar á að <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Veldu hvar á að <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"búa til aðgangslykla"</string>
<string name="save_your_password" msgid="6597736507991704307">"vistaðu aðgangsorðið"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"vistaðu innskráningarupplýsingarnar"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Stilltu sjálfgefna aðgangsorðastjórnun til að vista aðgangsorð og aðgangslykla og skrá þig hraðar inn næst."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Búa til aðgangslykil í <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Vista aðgangsorð í <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vista innskráningarupplýsingar í <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"aðgangslykill"</string>
<string name="password" msgid="6738570945182936667">"aðgangsorð"</string>
<string name="sign_ins" msgid="4710739369149469208">"innskráningar"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Búa til aðgangslykil í"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Vista aðgangsorð á"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Vista innskráningu á"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Viltu búa til aðgangslykil í öðru tæki?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Nota <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> fyrir allar innskráningar?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Þessi aðgangsorðastjórnun vistar aðgangsorð og aðgangslykla til að auðvelda þér að skrá þig inn."</string>
<string name="set_as_default" msgid="4415328591568654603">"Stilla sem sjálfgefið"</string>
<string name="use_once" msgid="9027366575315399714">"Nota einu sinni"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> aðgangsorð, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> aðgangslyklar"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> aðgangsorð"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> aðgangslyklar"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Aðgangslykill"</string>
<string name="another_device" msgid="5147276802037801217">"Annað tæki"</string>
<string name="other_password_manager" msgid="565790221427004141">"Önnur aðgangsorðastjórnun"</string>
<string name="close_sheet" msgid="1393792015338908262">"Loka blaði"</string>
diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml
index 3a7b0fb1ec3a..ddb2f3aa2efb 100644
--- a/packages/CredentialManager/res/values-it/strings.xml
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Salva in un altro luogo"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Usa un altro dispositivo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Salva su un altro dispositivo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un modo semplice per accedere in sicurezza"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa l\'impronta digitale, il volto o il blocco schermo per accedere con una passkey unica che non può essere dimenticata o rubata. Scopri di più"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Scegli dove <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Scegli dove <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"Crea le tue passkey"</string>
<string name="save_your_password" msgid="6597736507991704307">"salva la password"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"salva le tue informazioni di accesso"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Imposta un gestore delle password predefinito per salvare le tue password e passkey in modo da poter accedere più velocemente la prossima volta."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vuoi creare una passkey su <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Vuoi salvare la password su <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vuoi salvare le informazioni di accesso su <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="sign_ins" msgid="4710739369149469208">"accessi"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Crea passkey su"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Salva password su"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Salva accesso su"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vuoi creare una passkey su un altro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vuoi usare <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> per tutti gli accessi?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Questo gestore delle password archivierà le password e le passkey per aiutarti ad accedere facilmente."</string>
<string name="set_as_default" msgid="4415328591568654603">"Imposta come valore predefinito"</string>
<string name="use_once" msgid="9027366575315399714">"Usa una volta"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> password, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkey"</string>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
index 397ad60e79f7..50752eb3e3bd 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"שמירה במקום אחר"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"שימוש במכשיר אחר"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"שמירה במכשיר אחר"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"דרך פשוטה להיכנס לחשבון בבטחה"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"אפשר להשתמש בטביעת אצבע, בזיהוי פנים או בנעילת מסך כדי להיכנס לחשבון עם מפתח גישה ייחודי שאי אפשר לשכוח או לגנוב אותו. מידע נוסף"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"צריך לבחור לאן <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"צריך לבחור לאן <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"יצירת מפתחות גישה"</string>
<string name="save_your_password" msgid="6597736507991704307">"שמירת הסיסמה שלך"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"שמירת פרטי הכניסה שלך"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"יש לקבוע את מנהל הסיסמאות שיוגדר כברירת מחדל כדי לשמור את הסיסמאות ומפתחות הגישה, ולהיכנס לחשבון מהר יותר בפעם הבאה."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"ליצור מפתח גישה ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"לשמור את הסיסמה ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"לשמור את פרטי הכניסה ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"מפתח גישה"</string>
<string name="password" msgid="6738570945182936667">"סיסמה"</string>
<string name="sign_ins" msgid="4710739369149469208">"פרטי כניסה"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"יצירת מפתח גישה ב"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"שמירת הסיסמה של"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"שמירת פרטי הכניסה של"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"ליצור מפתח גישה במכשיר אחר?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"להשתמש ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> בכל הכניסות?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"במנהל הסיסמאות הזה יאוחסנו הסיסמאות ומפתחות הגישה שלך, כדי לעזור לך להיכנס לחשבון בקלות."</string>
<string name="set_as_default" msgid="4415328591568654603">"הגדרה כברירת מחדל"</string>
<string name="use_once" msgid="9027366575315399714">"שימוש פעם אחת"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> סיסמאות, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> מפתחות גישה"</string>
diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
index 0340b6698645..783a444b8a97 100644
--- a/packages/CredentialManager/res/values-ja/strings.xml
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"別の場所に保存"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"別のデバイスを使用"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"他のデバイスに保存"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"安全にログインする簡単な方法"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"忘れたり盗まれたりする可能性がある一意のパスキーと合わせて、ログインに指紋認証、顔認証、画面ロックを使用できます。詳細"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> の保存場所の選択"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> の保存場所の選択"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"パスキーの作成"</string>
<string name="save_your_password" msgid="6597736507991704307">"パスワードを保存"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ログイン情報を保存"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"デフォルトのパスワード マネージャーを設定すると、パスワードやパスキーを保存して、次回から素早くログインできるようになります。"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> でパスキーを作成しますか?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> にパスワードを保存しますか?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> にログイン情報を保存しますか?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"パスキー"</string>
<string name="password" msgid="6738570945182936667">"パスワード"</string>
<string name="sign_ins" msgid="4710739369149469208">"ログイン"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"パスキーの作成先"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"パスワードの保存先"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ログイン情報の保存先"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"他のデバイスでパスキーを作成しますか?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ログインのたびに <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> を使用しますか?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"このパスワード マネージャーに、パスワードやパスキーが保存され、簡単にログインできるようになります。"</string>
<string name="set_as_default" msgid="4415328591568654603">"デフォルトに設定"</string>
<string name="use_once" msgid="9027366575315399714">"1 回使用"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 件のパスワード、<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 件のパスキー"</string>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index 3da7ea394c60..eba01d4c0a86 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"სხვა სივრცეში შენახვა"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"სხვა მოწყობილობის გამოყენება"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"სხვა მოწყობილობაზე შენახვა"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"უსაფრთხოდ შესვლის მარტივი გზა"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"გამოიყენეთ თქვენი თითის ანაბეჭდი, სახის ამოცნობა და ეკრანის დაბლოკვა სისტემაში უნიკალური წვდომის გასაღებით შესასვლელად, რომლის დავიწყება ან მოპარვა შეუძლებელია. შეიტყვეთ მეტი"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"აირჩიეთ, სად უნდა <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"აირჩიეთ, სად უნდა <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"შექმენით თქვენი პაროლი"</string>
<string name="save_your_password" msgid="6597736507991704307">"შეინახეთ თქვენი პაროლი"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"შეინახეთ თქვენი სისტემაში შესვლის ინფორმაცია"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"დააყენეთ პაროლის ნაგულისხმევი მენეჯერი, რათა შეინახოთ თქვენი პაროლები და გასაღებები და შეხვიდეთ უფრო სწრაფად შემდეგ ჯერზე."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"გსურთ წვდომის გასაღების შექმნა <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-ში?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"გსურთ თქვენი პაროლის შენახვა <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-ში?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"გსურთ თქვენი სისტემაში შესვლის მონაცემების შენახვა <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-ში?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"წვდომის გასაღები"</string>
<string name="password" msgid="6738570945182936667">"პაროლი"</string>
<string name="sign_ins" msgid="4710739369149469208">"სისტემაში შესვლა"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"წვდომის გასაღების შექმნა"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"პაროლის შენახვა"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"შესვლის შენახვა"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"გსურთ პაროლის შექმნა სხვა მოწყობილობაში?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"გსურთ, გამოიყენოთ<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> სისტემაში ყველა შესვლისთვის?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"მოცემული პაროლების მმართველი შეინახავს თქვენს პაროლებს და წვდომის გასაღებს, რომლებიც დაგეხმარებათ სისტემაში მარტივად შესვლაში."</string>
<string name="set_as_default" msgid="4415328591568654603">"ნაგულისხმევად დაყენება"</string>
<string name="use_once" msgid="9027366575315399714">"ერთხელ გამოყენება"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> პაროლი, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> წვდომის გასაღები"</string>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index 9491f8e83d6b..d7d255b63c07 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Тіркелу деректері менеджері"</string>
<string name="string_cancel" msgid="6369133483981306063">"Бас тарту"</string>
<string name="string_continue" msgid="1346732695941131882">"Жалғастыру"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Басқа орында жасау"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Басқа орынға сақтау"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Басқа құрылғыны пайдалану"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Басқа құрылғыға сақтау"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Қауіпсіз кірудің оңай жолы"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Ұмытылмайтын немесе ұрланбайтын бірегей кіру кілтінің көмегімен кіру үшін саусақ ізін, бетті анықтау функциясын немесе экран құлпын пайдаланыңыз. Толық ақпарат"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> таңдау"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> таңдау"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"кіру кілттерін жасаңыз"</string>
<string name="save_your_password" msgid="6597736507991704307">"құпия сөзді сақтау"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"тіркелу деректерін сақтау"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Құпия сөздер мен кіру кілттерін сақтап, келесі рет жылдам кіру үшін әдепкі құпия сөз менеджерін орнатыңыз."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> қолданбасында кіру кілті жасалсын ба?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> қолданбасына құпия сөз сақталсын ба?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> қолданбасына тіркелу деректері сақталсын ба?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"кіру кілті"</string>
<string name="password" msgid="6738570945182936667">"құпия сөз"</string>
<string name="sign_ins" msgid="4710739369149469208">"кіру әрекеттері"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Кіру кілтін жасау"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Құпия сөзді келесіге сақтау:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Кіру деректерін келесіге сақтау:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Кіру кілті басқа құрылғыда жасалсын ба?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Барлық кіру әрекеті үшін <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> пайдаланылсын ба?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Аккаунтқа оңай кіру үшін құпия сөз менеджері құпия сөздер мен кіру кілттерін сақтайды."</string>
<string name="set_as_default" msgid="4415328591568654603">"Әдепкі етіп орнату"</string>
<string name="use_once" msgid="9027366575315399714">"Бір рет пайдалану"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> құпия сөз, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> кіру кілті"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> құпия сөз"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> кіру кілті"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Кіру кілті"</string>
<string name="another_device" msgid="5147276802037801217">"Басқа құрылғы"</string>
<string name="other_password_manager" msgid="565790221427004141">"Басқа құпия сөз менеджерлері"</string>
<string name="close_sheet" msgid="1393792015338908262">"Парақты жабу"</string>
diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml
index 80167fc36e35..b10466149c57 100644
--- a/packages/CredentialManager/res/values-km/strings.xml
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"កម្មវិធី​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទៀងផ្ទាត់"</string>
<string name="string_cancel" msgid="6369133483981306063">"បោះបង់"</string>
<string name="string_continue" msgid="1346732695941131882">"បន្ត"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"បង្កើតនៅកន្លែងផ្សេងទៀត"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"រក្សាទុកក្នុងកន្លែងផ្សេងទៀត"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"ប្រើ​ឧបករណ៍​ផ្សេងទៀត"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"រក្សាទុកទៅក្នុងឧបករណ៍ផ្សេង"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"វិធីដ៏សាមញ្ញ ដើម្បីចូលគណនីដោយសុវត្ថិភាព"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ប្រើស្នាមម្រាមដៃ មុខ ឬការចាក់សោអេក្រង់របស់អ្នក ដើម្បីចូលគណនីដោយប្រើកូដសម្ងាត់ខុសប្លែកពីគេដែលមិនអាចភ្លេច ឬត្រូវគេលួច។ ស្វែងយល់បន្ថែម"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"ជ្រើសរើសកន្លែងដែលត្រូវ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"ជ្រើសរើសកន្លែងដែលត្រូវ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"បង្កើត​កូដសម្ងាត់របស់អ្នក"</string>
<string name="save_your_password" msgid="6597736507991704307">"រក្សាទុកពាក្យសម្ងាត់របស់អ្នក"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"រក្សាទុកព័ត៌មានចូលគណនីរបស់អ្នក"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"កំណត់​កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់​លំនាំដើម ដើម្បីរក្សាទុក​ពាក្យសម្ងាត់និង​កូដសម្ងាត់របស់អ្នក និងចូលគណនី​កាន់តែរហ័ស​នៅពេលលើកក្រោយ។"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"បង្កើតកូដសម្ងាត់នៅក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ឬ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"រក្សាទុកពាក្យសម្ងាត់របស់អ្នកក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ឬ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"រក្សាទុកព័ត៌មានចូលគណនីរបស់អ្នកក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ឬ?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"កូដសម្ងាត់"</string>
<string name="password" msgid="6738570945182936667">"ពាក្យសម្ងាត់"</string>
<string name="sign_ins" msgid="4710739369149469208">"ការចូល​គណនី"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"បង្កើតកូដសម្ងាត់នៅក្នុង"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"រក្សាទុក​ពាក្យសម្ងាត់ទៅ"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"រក្សាទុក​ការចូល​គណនីទៅ"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"បង្កើតកូដសម្ងាត់​នៅក្នុងឧបករណ៍​ផ្សេងទៀតឬ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ប្រើ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> សម្រាប់ការចូលគណនីទាំងអស់របស់អ្នកឬ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់នេះ​នឹងរក្សាទុកពាក្យសម្ងាត់ និងកូដសម្ងាត់​របស់អ្នក ដើម្បីជួយឱ្យអ្នក​ចូលគណនី​បានយ៉ាងងាយស្រួល។"</string>
<string name="set_as_default" msgid="4415328591568654603">"កំណត់ជាលំនាំដើម"</string>
<string name="use_once" msgid="9027366575315399714">"ប្រើម្ដង"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"ពាក្យសម្ងាត់ <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> កូដសម្ងាត់ <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"ពាក្យសម្ងាត់ <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"កូដសម្ងាត់ <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"កូដសម្ងាត់"</string>
<string name="another_device" msgid="5147276802037801217">"ឧបករណ៍​ផ្សេងទៀត"</string>
<string name="other_password_manager" msgid="565790221427004141">"កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ផ្សេងទៀត"</string>
<string name="close_sheet" msgid="1393792015338908262">"បិទសន្លឹក"</string>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
index 96304ac96d3b..033eec1df02c 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"ಮತ್ತೊಂದು ಸ್ಥಳದಲ್ಲಿ ಉಳಿಸಿ"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"ಬೇರೊಂದು ಸಾಧನವನ್ನು ಬಳಸಿ"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"ಬೇರೊಂದು ಸಾಧನದಲ್ಲಿ ಉಳಿಸಿ"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"ಸುರಕ್ಷಿತವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡುವ ಸುಲಭ ವಿಧಾನ"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ಮರೆಯಲಾಗದ ಅಥವಾ ಕದಿಯಲಾಗದ ಅನನ್ಯ ಪಾಸ್‌ಕೀ ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್, ಫೇಸ್ ಲಾಕ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಬಳಸಿ. ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ಅನ್ನು ಎಲ್ಲಿ ಉಳಿಸಬೇಕು ಎಂದು ಆಯ್ಕೆಮಾಡಿ"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ಅನ್ನು ಎಲ್ಲಿ ಉಳಿಸಬೇಕು ಎಂದು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ನಿಮ್ಮ ಪಾಸ್‌ಕೀಗಳನ್ನು ರಚಿಸಿ"</string>
<string name="save_your_password" msgid="6597736507991704307">"ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಉಳಿಸಿ"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ನಿಮ್ಮ ಸೈನ್-ಇನ್ ಮಾಹಿತಿ ಉಳಿಸಿ"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಾಸ್‌ಕೀಗಳನ್ನು ಉಳಿಸಲು ಡೀಫಾಲ್ಟ್ ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕವನ್ನು ಸೆಟ್ ಮಾಡಿ ಹಾಗೂ ಮುಂದಿನ ಬಾರಿ ವೇಗವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡಿ."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ನಲ್ಲಿ ಪಾಸ್‌ಕೀ ರಚಿಸಬೇಕೆ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಗೆ ಉಳಿಸಬೇಕೆ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ನಿಮ್ಮ ಸೈನ್ ಇನ್ ಮಾಹಿತಿಯನ್ನು <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಗೆ ಉಳಿಸಬೇಕೆ?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"ಪಾಸ್‌ಕೀ"</string>
<string name="password" msgid="6738570945182936667">"ಪಾಸ್‌ವರ್ಡ್"</string>
<string name="sign_ins" msgid="4710739369149469208">"ಸೈನ್-ಇನ್‌ಗಳು"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ಇಲ್ಲಿ ಪಾಸ್‌ಕೀ ರಚಿಸಿ"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"ಇಲ್ಲಿಗೆ ಪಾಸ್‌ವರ್ಡ್ ಉಳಿಸಿ"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ಇಲ್ಲಿಗೆ ಸೈನ್-ಇನ್ ಮಾಹಿತಿ ಉಳಿಸಿ"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"ಮತ್ತೊಂದು ಸಾಧನದಲ್ಲಿ ಪಾಸ್‌ಕೀ ರಚಿಸಬೇಕೆ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ನಿಮ್ಮ ಎಲ್ಲಾ ಸೈನ್-ಇನ್‌ಗಳಿಗಾಗಿ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸುವುದೇ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"ಈ ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕವು ನಿಮಗೆ ಸುಲಭವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡುವುದಕ್ಕೆ ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಾಸ್‌ಕೀಗಳನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ."</string>
<string name="set_as_default" msgid="4415328591568654603">"ಡೀಫಾಲ್ಟ್ ಆಗಿ ಸೆಟ್ ಮಾಡಿ"</string>
<string name="use_once" msgid="9027366575315399714">"ಒಂದು ಬಾರಿ ಬಳಸಿ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ಪಾಸ್‌ಕೀಗಳು"</string>
diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml
index 58518c16ace4..44f22d76a546 100644
--- a/packages/CredentialManager/res/values-ko/strings.xml
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"인증서 관리자"</string>
<string name="string_cancel" msgid="6369133483981306063">"취소"</string>
<string name="string_continue" msgid="1346732695941131882">"계속"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"다른 위치에 만들기"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"다른 위치에 저장"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"다른 기기 사용"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"다른 기기에 저장"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"안전하게 로그인하는 간단한 방법"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"지문, 얼굴 인식 또는 화면 잠금을 통해 잊어버리거나 분실할 염려가 없는 고유한 패스키로 로그인하세요. 자세히 알아보기"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> 작업을 위한 위치 선택"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> 작업을 위한 위치 선택"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"패스키 만들기"</string>
<string name="save_your_password" msgid="6597736507991704307">"비밀번호 저장"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"로그인 정보 저장"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"기본 비밀번호 관리자를 설정하여 비밀번호와 패스키를 저장하고 다음에 더 빠르게 로그인하세요."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>에 패스키를 만드시겠습니까?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>에 비밀번호를 저장하시겠습니까?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>에 로그인 정보를 저장하시겠습니까?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"패스키"</string>
<string name="password" msgid="6738570945182936667">"비밀번호"</string>
<string name="sign_ins" msgid="4710739369149469208">"로그인 정보"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"다음 위치에 패스키 만들기"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"비밀번호를 다음에 저장"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"로그인 정보를 다음에 저장"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"다른 기기에서 패스키를 만들까요?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"모든 로그인에 <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>을(를) 사용하시겠습니까?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"이 비밀번호 관리자는 비밀번호와 패스키를 저장하여 사용자가 간편하게 로그인하도록 돕습니다."</string>
<string name="set_as_default" msgid="4415328591568654603">"기본값으로 설정"</string>
<string name="use_once" msgid="9027366575315399714">"한 번 사용"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"비밀번호 <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>개, 패스키 <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>개"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"비밀번호 <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>개"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"패스키 <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>개"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"패스키"</string>
<string name="another_device" msgid="5147276802037801217">"다른 기기"</string>
<string name="other_password_manager" msgid="565790221427004141">"기타 비밀번호 관리자"</string>
<string name="close_sheet" msgid="1393792015338908262">"시트 닫기"</string>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
index 298657eb8eaa..c4621cfde407 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
<string name="string_cancel" msgid="6369133483981306063">"Жок"</string>
<string name="string_continue" msgid="1346732695941131882">"Улантуу"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Башка жерде түзүү"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Башка жерге сактоо"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Башка түзмөк колдонуу"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Башка түзмөккө сактоо"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Коопсуз кирүүнүн жөнөкөй жолу"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Унутуп калууга же уурдатууга мүмкүн эмес болгон уникалдуу ачкыч менен манжа изин, жүзүнөн таанып ачуу же экранды кулпулоо функцияларын колдонуп өзүңүздү ырастай аласыз. Кененирээк"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> үчүн жер тандаңыз"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> үчүн жер тандаңыз"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"мүмкүндүк алуу ачкычтарын түзүү"</string>
<string name="save_your_password" msgid="6597736507991704307">"сырсөзүңүздү сактаңыз"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"кирүү маалыматын сактаңыз"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Сырсөздөр менен мүмкүндүк алуу ачкычтары сактала турган демейки сырсөздөрдү башкаргычты тандап, кийинки жолу аккаунтуңузга тезирээк кириңиз."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> колдонмосунда мүмкүндүк алуу ачкычын түзөсүзбү?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Сырсөзүңүздү <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> колдонмосунда сактайсызбы?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Кирүү маалыматын <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> колдонмосунда сактайсызбы?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"мүмкүндүк алуу ачкычы"</string>
<string name="password" msgid="6738570945182936667">"сырсөз"</string>
<string name="sign_ins" msgid="4710739369149469208">"кирүүлөр"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Мүмкүндүк алуу ачкычын бул жерден түзүү:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Сырсөздү каякка сактайсыз:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Аккаунтка кирүү маалыматын каякка сактайсыз:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Мүмкүндүк алуу ачкычы башка түзмөктө түзүлсүнбү?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> бардык аккаунттарга кирүү үчүн колдонулсунбу?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Сырсөздөрүңүздү жана ачкычтарыңызды Сырсөздөрдү башкаргычка сактап коюп, каалаган убакта колдоно берсеңиз болот."</string>
<string name="set_as_default" msgid="4415328591568654603">"Демейки катары коюу"</string>
<string name="use_once" msgid="9027366575315399714">"Бир жолу колдонуу"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> сырсөз, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> мүмкүндүк алуу ачкычы"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> сырсөз"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> мүмкүндүк алуу ачкычы"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Мүмкүндүк алуу ачкычы"</string>
<string name="another_device" msgid="5147276802037801217">"Башка түзмөк"</string>
<string name="other_password_manager" msgid="565790221427004141">"Башка сырсөздөрдү башкаргычтар"</string>
<string name="close_sheet" msgid="1393792015338908262">"Баракты жабуу"</string>
diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml
index 215262bc4943..7429389fac0a 100644
--- a/packages/CredentialManager/res/values-lo/strings.xml
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"ຕົວຈັດການຂໍ້ມູນການເຂົ້າສູ່ລະບົບ"</string>
<string name="string_cancel" msgid="6369133483981306063">"ຍົກເລີກ"</string>
<string name="string_continue" msgid="1346732695941131882">"ສືບຕໍ່"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"ສ້າງໃນບ່ອນອື່ນ"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"ບັນທຶກໃສ່ບ່ອນອື່ນ"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"ໃຊ້ອຸປະກອນອື່ນ"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"ບັນທຶກໃສ່ອຸປະກອນອື່ນ"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"ວິທີງ່າຍໆໃນການເຂົ້າສູ່ລະບົບຢ່າງປອດໄພ"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ໃຊ້ລາຍນິ້ວມື, ໃບໜ້າ ຫຼື ລັອກໜ້າຈໍຂອງທ່ານເພື່ອເຂົ້າສູ່ລະບົບດ້ວຍກະແຈຜ່ານທີ່ບໍ່ຊ້ຳກັນເພື່ອບໍ່ໃຫ້ລືມ ຫຼື ຖືກລັກໄດ້. ສຶກສາເພີ່ມເຕີມ"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"ເລືອກບ່ອນທີ່ຈະ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"ເລືອກບ່ອນທີ່ຈະ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ສ້າງກະແຈຜ່ານຂອງທ່ານ"</string>
<string name="save_your_password" msgid="6597736507991704307">"ບັນທຶກລະຫັດຜ່ານຂອງທ່ານ"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບຂອງທ່ານ"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"ຕັ້ງຄ່າເລີ່ມຕົ້ນຂອງຕົວຈັດການລະຫັດຜ່ານເພື່ອບັນທຶກລະຫັດຜ່ານ ແລະ ກະແຈຜ່ານຂອງທ່ານ ແລະ ເຂົ້າສູ່ລະບົບໄດ້ໄວຂຶ້ນໃນເທື່ອຕໍ່ໄປ."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"ສ້າງກະແຈຜ່ານໃນ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ບໍ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"ບັນທຶກລະຫັດຜ່ານຂອງທ່ານໃສ່ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ບໍ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບຂອງທ່ານໃສ່ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ບໍ?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"ກະແຈຜ່ານ"</string>
<string name="password" msgid="6738570945182936667">"ລະຫັດຜ່ານ"</string>
<string name="sign_ins" msgid="4710739369149469208">"ການເຂົ້າສູ່ລະບົບ"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ສ້າງກະແຈຜ່ານໃນ"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"ບັນທຶກລະຫັດຜ່ານໃສ່"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ບັນທຶກການເຂົ້າສູ່ລະບົບໃສ່"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"ສ້າງກະແຈຜ່ານໃນອຸປະກອນອື່ນບໍ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ໃຊ້ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ສຳລັບການເຂົ້າສູ່ລະບົບທັງໝົດຂອງທ່ານບໍ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"ຕົວຈັດການລະຫັດຜ່ານນີ້ຈະຈັດເກັບລະຫັດຜ່ານ ແລະ ກະແຈຜ່ານຂອງທ່ານໄວ້ເພື່ອຊ່ວຍໃຫ້ທ່ານເຂົ້າສູ່ລະບົບໄດ້ໂດຍງ່າຍ."</string>
<string name="set_as_default" msgid="4415328591568654603">"ຕັ້ງເປັນຄ່າເລີ່ມຕົ້ນ"</string>
<string name="use_once" msgid="9027366575315399714">"ໃຊ້ເທື່ອດຽວ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ລະຫັດຜ່ານ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ກະແຈຜ່ານ"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ລະຫັດຜ່ານ"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ກະແຈຜ່ານ"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"ກະແຈຜ່ານ"</string>
<string name="another_device" msgid="5147276802037801217">"ອຸປະກອນອື່ນ"</string>
<string name="other_password_manager" msgid="565790221427004141">"ຕົວຈັດການລະຫັດຜ່ານອື່ນໆ"</string>
<string name="close_sheet" msgid="1393792015338908262">"ປິດຊີດ"</string>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
index 6125fe3f2b7b..aa5d97a6e87b 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Išsaugoti kitoje vietoje"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Naudoti kitą įrenginį"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Išsaugoti kitame įrenginyje"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Paprastas saugaus prisijungimo metodas"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Naudodami piršto atspaudą, veidą ar ekrano užraktą prisijunkite su unikaliu „passkey“, kurio neįmanoma pamiršti ar pavogti. Sužinokite daugiau"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Pasirinkite, kur <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Pasirinkite, kur <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"kurkite slaptažodžius"</string>
<string name="save_your_password" msgid="6597736507991704307">"išsaugoti slaptažodį"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"išsaugoti prisijungimo informaciją"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Nustatykite numatytąją slaptažodžių tvarkyklę, kad išsaugotumėte slaptažodžius ir kitą kartą galėtumėte sparčiau prisijungti."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Sukurti „passkey“ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Išsaugoti slaptažodį <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Išsaugoti prisijungimo informaciją <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"„passkey“"</string>
<string name="password" msgid="6738570945182936667">"slaptažodis"</string>
<string name="sign_ins" msgid="4710739369149469208">"prisijungimo informacija"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Slaptažodžio kūrimas"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Išsaugoti slaptažodį"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Išsaugoti prisijungimo informaciją"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Sukurti slaptažodį kitame įrenginyje?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Naudoti <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> visada prisijungiant?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Šioje slaptažodžių tvarkyklėje bus saugomi jūsų slaptažodžiai, kad galėtumėte lengvai prisijungti."</string>
<string name="set_as_default" msgid="4415328591568654603">"Nustatyti kaip numatytąjį"</string>
<string name="use_once" msgid="9027366575315399714">"Naudoti vieną kartą"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"slaptažodžių: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, „passkey“: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml
index 43c036fde4bb..06446ab91b85 100644
--- a/packages/CredentialManager/res/values-lv/strings.xml
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Saglabāt citur"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Izmantot citu ierīci"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Saglabāt citā ierīcē"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Vienkāršs veids, kā droši pierakstīties"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Izmantojiet pirksta nospiedumu, autorizāciju pēc sejas vai ekrāna bloķēšanu, lai pierakstītos ar unikālu piekļuves atslēgu, ko nevar aizmirst vai nozagt. Uzziniet vairāk."</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Izvēlieties, kur: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Izvēlieties, kur: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"veidot piekļuves atslēgas"</string>
<string name="save_your_password" msgid="6597736507991704307">"saglabāt paroli"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"saglabāt pierakstīšanās informāciju"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Iestatiet noklusējuma paroļu pārvaldnieku, lai saglabātu paroles un piekļuves atslēgas un nākamajā reizē pierakstītos ātrāk."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vai izveidot piekļuves atslēgu šeit: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Vai saglabāt paroli šeit: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vai saglabāt pierakstīšanās informāciju šeit: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"piekļuves atslēga"</string>
<string name="password" msgid="6738570945182936667">"parole"</string>
<string name="sign_ins" msgid="4710739369149469208">"pierakstīšanās informācija"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Izveidot piekļuves atslēgu šeit:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Saglabāt paroli šeit:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Saglabāt pierakstīšanās informāciju šeit:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vai izveidot piekļuves atslēgu citā ierīcē?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vai vienmēr izmantot <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>, lai pierakstītos?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Šis paroļu pārvaldnieks glabās jūsu paroles un piekļuves atslēgas, lai atvieglotu pierakstīšanos."</string>
<string name="set_as_default" msgid="4415328591568654603">"Iestatīt kā noklusējumu"</string>
<string name="use_once" msgid="9027366575315399714">"Izmantot vienreiz"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> paroles, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> piekļuves atslēgas"</string>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
index 059f04207958..8093d7444b49 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Зачувајте на друго место"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Употребете друг уред"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Зачувајте на друг уред"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Едноставен начин за безбедно најавување"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Користете го отпечатокот, заклучувањето со лик или заклучувањето екран за да се најавите со единствен криптографски клуч што не може да се заборави или украде. Дознајте повеќе"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Изберете каде да <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Изберете каде да <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"создајте криптографски клучеви"</string>
<string name="save_your_password" msgid="6597736507991704307">"се зачува лозинката"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"се зачуваат податоците за најавување"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Поставете стандарден управник со лозинки за да ги складира вашите лозинки и криптографски клучеви и најавете се побрзо следниот пат."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Да се создаде криптографски клуч во <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Да се зачува вашата лозинка во <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Да се зачуваат вашите податоци за најавување во <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"криптографски клуч"</string>
<string name="password" msgid="6738570945182936667">"лозинка"</string>
<string name="sign_ins" msgid="4710739369149469208">"најавувања"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Создајте криптографски клуч во"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Зачувајте ја лозинката во"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Зачувајте го најавувањето во"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Да се создаде криптографски клуч во друг уред?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Да се користи <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> за сите ваши најавувања?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Овој управник со лозинки ќе ги складира вашите лозинки и криптографски клучеви за да ви помогне лесно да се најавите."</string>
<string name="set_as_default" msgid="4415328591568654603">"Постави како стандардна опција"</string>
<string name="use_once" msgid="9027366575315399714">"Употребете еднаш"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> лозинки, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> криптографски клучеви"</string>
diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
index e4f6d6972698..68a641984e4a 100644
--- a/packages/CredentialManager/res/values-ml/strings.xml
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"മറ്റൊരു സ്ഥലത്തേക്ക് സംരക്ഷിക്കുക"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"മറ്റൊരു ഉപകരണം ഉപയോഗിക്കുക"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"മറ്റൊരു ഉപകരണത്തിലേക്ക് സംരക്ഷിക്കുക"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"സുരക്ഷിതമായി സൈൻ ഇൻ ചെയ്യാനുള്ള ലളിതമായ മാർഗ്ഗം"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"മറന്നുപോകാനും മോഷ്‌ടിക്കാനും സാധ്യതയില്ലാത്ത തനത് പാസ്‌കീ ഉപയോഗിച്ച് സൈൻ ഇൻ ചെയ്യാൻ നിങ്ങളുടെ ഫിംഗർപ്രിന്റോ മുഖമോ സ്‌ക്രീൻ ലോക്കോ ഉപയോഗിക്കുക. കൂടുതലറിയുക"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"എവിടെ <xliff:g id="CREATETYPES">%1$s</xliff:g> എന്ന് തിരഞ്ഞെടുക്കുക"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"എവിടെ <xliff:g id="CREATETYPES">%1$s</xliff:g> എന്ന് തിരഞ്ഞെടുക്കുക"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"നിങ്ങളുടെ പാസ്‌കീകൾ സൃഷ്‌ടിക്കുക"</string>
<string name="save_your_password" msgid="6597736507991704307">"നിങ്ങളുടെ പാസ്‌വേഡ് സംരക്ഷിക്കുക"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"നിങ്ങളുടെ സൈൻ ഇൻ വിവരങ്ങൾ സംരക്ഷിക്കുക"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"നിങ്ങളുടെ പാസ്‌വേഡുകളും പാസ്‌കീകളും സംരക്ഷിക്കാനും അടുത്ത തവണ വേഗത്തിൽ സൈൻ ഇൻ ചെയ്യാനും ഒരു ഡിഫോൾട്ട് പാസ്‌വേഡ് മാനേജർ സജ്ജീകരിക്കുക."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> എന്നതിൽ ഒരു പാസ്‌കീ സൃഷ്‌ടിക്കണോ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"പാസ്‌വേഡ് <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> എന്നതിലേക്ക് സംരക്ഷിക്കണോ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"സൈൻ ഇൻ വിവരങ്ങൾ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> എന്നതിലേക്ക് സംരക്ഷിക്കണോ?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"പാസ്‌കീ"</string>
<string name="password" msgid="6738570945182936667">"പാസ്‌വേഡ്"</string>
<string name="sign_ins" msgid="4710739369149469208">"സൈൻ ഇന്നുകൾ"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ഇനിപ്പറയുന്നതിൽ പാസ്‌കീ സൃഷ്‌ടിക്കുക"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"പാസ്‌വേഡ് ഇനിപ്പറയുന്നതിൽ സംരക്ഷിക്കുക"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ഇനിപ്പറയുന്നതിലേക്ക് സൈൻ ഇൻ സംരക്ഷിക്കുക"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"മറ്റൊരു ഉപകരണത്തിൽ പാസ്‌കീ സൃഷ്ടിക്കണോ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"നിങ്ങളുടെ എല്ലാ സൈൻ ഇന്നുകൾക്കും <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ഉപയോഗിക്കണോ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"എളുപ്പത്തിൽ സൈൻ ഇൻ ചെയ്യാൻ സഹായിക്കുന്നതിന് ഈ പാസ്‌വേഡ് മാനേജർ നിങ്ങളുടെ പാസ്‌വേഡുകളും പാസ്‌കീകളും സംഭരിക്കും."</string>
<string name="set_as_default" msgid="4415328591568654603">"ഡിഫോൾട്ടായി സജ്ജീകരിക്കുക"</string>
<string name="use_once" msgid="9027366575315399714">"ഒരു തവണ ഉപയോഗിക്കുക"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> പാസ്‌വേഡുകൾ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> പാസ്‌കീകൾ"</string>
diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
index 3f8d4caafafe..40ef5e55fffa 100644
--- a/packages/CredentialManager/res/values-mn/strings.xml
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Өөр газар хадгалах"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Өөр төхөөрөмж ашиглах"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Өөр төхөөрөмжид хадгалах"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Аюулгүй нэвтрэх энгийн арга"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Мартах эсвэл хулгайд алдах боломжгүй өвөрмөц passkey-н хамт нэвтрэх хурууны хээ, царай эсвэл дэлгэцийн түгжээгээ ашиглана уу. Нэмэлт мэдээлэл авах"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Хаана <xliff:g id="CREATETYPES">%1$s</xliff:g>-г сонгоно уу"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Хаана <xliff:g id="CREATETYPES">%1$s</xliff:g>-г сонгоно уу"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"passkey-үүдээ үүсгэнэ үү"</string>
<string name="save_your_password" msgid="6597736507991704307">"нууц үгээ хадгалах"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"нэвтрэх мэдээллээ хадгалах"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Нууц үгнүүд болон passkey-г хадгалах болон дараагийн удаа илүү хурдан нэвтрэхийн тулд өгөгдмөл нууц үгний менежерийг тохируулна уу"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-д passkey үүсгэх үү?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Нууц үгээ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-д хадгалах уу?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Нэвтрэх мэдээллээ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-д хадгалах уу?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"нууц үг"</string>
<string name="sign_ins" msgid="4710739369149469208">"нэвтрэлт"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Дараахад passkey үүсгэх"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Нууц үгийг дараахад хадгалах"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Нэвтрэх мэдээллийг дараахад хадгалах"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Өөр төхөөрөмжид passkey үүсгэх үү?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-г бүх нэвтрэлтдээ ашиглах уу?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Танд хялбархан нэвтрэхэд туслахын тулд энэ нууц үгний менежер таны нууц үг болон passkey-г хадгална."</string>
<string name="set_as_default" msgid="4415328591568654603">"Өгөгдмөлөөр тохируулах"</string>
<string name="use_once" msgid="9027366575315399714">"Нэг удаа ашиглах"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> нууц үг, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkey"</string>
diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml
index aa6f2537842a..60c969d9832e 100644
--- a/packages/CredentialManager/res/values-mr/strings.xml
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"क्रेडेंशियल व्यवस्थापक"</string>
<string name="string_cancel" msgid="6369133483981306063">"रद्द करा"</string>
<string name="string_continue" msgid="1346732695941131882">"पुढे सुरू ठेवा"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"दुसऱ्या ठिकाणी तयार करा"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"दुसऱ्या ठिकाणी सेव्ह करा"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"दुसरे डिव्‍हाइस वापरा"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"दुसऱ्या डिव्हाइसवर सेव्ह करा"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"सुरक्षितपणे साइन इन करण्याचा सोपा मार्ग"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"युनिक पासकीसह साइन इन करण्यासाठी तुमचे फिंगरप्रिंट, फेस किंवा स्क्रीन लॉक वापरा, जे विसरता येणार नाही किंवा चोरीला जाणार नाही. अधिक जाणून घ्या"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> कुठे करायचे ते निवडा"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> कुठे करायचे ते निवडा"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"तुमच्या पासकी तयार करा"</string>
<string name="save_your_password" msgid="6597736507991704307">"तुमचा पासवर्ड सेव्ह करा"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"तुमची साइन-इन माहिती सेव्ह करा"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"तुमचे पासवर्ड आणि पासकी सेव्ह करण्यासाठी डीफॉल्ट पासवर्ड मॅनेजर सेट करा व पुढच्या वेळी आणखी जलद साइन इन करा."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मध्ये पासकी तयार करायची का?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"तुमचा पासवर्ड <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> वर सेव्ह करायचा का?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"तुमची साइन-इन माहिती <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> वर सेव्ह करायची का?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"पासकी"</string>
<string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
<string name="sign_ins" msgid="4710739369149469208">"साइन-इन"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"यामध्ये पासकी तयार करा"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"यावर पासवर्ड सेव्ह करा"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"यावर साइन-इन सेव्ह करा"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"दुसऱ्या डिव्हाइसमध्ये पासकी तयार करायची आहे का?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"तुमच्या सर्व साइन-इन साठी <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>वापरायचे का?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"तुम्हाला सहजरीत्या साइन इन करण्यात मदत करण्यासाठी हा पासवर्ड व्यवस्थापक तुमचे पासवर्ड आणि पासकी स्टोअर करेल."</string>
<string name="set_as_default" msgid="4415328591568654603">"डिफॉल्ट म्हणून सेट करा"</string>
<string name="use_once" msgid="9027366575315399714">"एकदा वापरा"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> पासकी"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> पासकी"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"पासकी"</string>
<string name="another_device" msgid="5147276802037801217">"इतर डिव्हाइस"</string>
<string name="other_password_manager" msgid="565790221427004141">"इतर पासवर्ड व्यवस्थापक"</string>
<string name="close_sheet" msgid="1393792015338908262">"शीट बंद करा"</string>
diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml
index d5f8c0e59bca..a590e9598d74 100644
--- a/packages/CredentialManager/res/values-ms/strings.xml
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Simpan di tempat lain"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Gunakan peranti lain"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Simpan kepada peranti lain"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Cara mudah untuk log masuk dengan selamat"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gunakan cap jari, wajah atau kunci skrin anda untuk log masuk menggunakan kunci laluan unik yang tidak boleh dilupakan atau dicuri. Ketahui lebih lanjut"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"buat kunci laluan anda"</string>
<string name="save_your_password" msgid="6597736507991704307">"simpan kata laluan anda"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"simpan maklumat log masuk anda"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Tetapkan pengurus kata laluan lalai untuk menyimpan kata laluan dan kunci laluan dan log masuk dengan lebih pantas pada masa akan datang."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Buat kunci laluan dalam <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Simpan kata laluan anda pada <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Simpan maklumat log masuk anda pada <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"kunci laluan"</string>
<string name="password" msgid="6738570945182936667">"kata laluan"</string>
<string name="sign_ins" msgid="4710739369149469208">"log masuk"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Buat kunci laluan dalam"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Simpan kata laluan pada"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Simpan maklumat log masuk pada"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Buat kunci laluan dalam peranti lain?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua log masuk anda?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Pengurus kata laluan ini akan menyimpan kata laluan dan kunci laluan anda untuk membantu anda log masuk dengan mudah."</string>
<string name="set_as_default" msgid="4415328591568654603">"Tetapkan sebagai lalai"</string>
<string name="use_once" msgid="9027366575315399714">"Gunakan sekali"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Kata laluan <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, kunci laluan <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml
index eda2f741eda7..c7c88a7f60cf 100644
--- a/packages/CredentialManager/res/values-my/strings.xml
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"အထောက်အထားမန်နေဂျာ"</string>
<string name="string_cancel" msgid="6369133483981306063">"မလုပ်တော့"</string>
<string name="string_continue" msgid="1346732695941131882">"ရှေ့ဆက်ရန်"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"နောက်တစ်နေရာတွင် ပြုလုပ်ရန်"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"နောက်တစ်နေရာတွင် သိမ်းရန်"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"စက်နောက်တစ်ခု သုံးရန်"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"စက်နောက်တစ်ခုတွင် သိမ်းရန်"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"လုံခြုံစွာလက်မှတ်ထိုးဝင်ရန် ရိုးရှင်းသောနည်း"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"မေ့မသွား (သို့) ခိုးမသွားနိုင်သော သီးခြားလျှို့ဝှက်ကီးဖြင့် လက်မှတ်ထိုးဝင်ရန် သင့်လက်ဗွေ၊ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ် သုံးနိုင်သည်။ ပိုမိုလေ့လာရန်"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ရန် နေရာရွေးပါ"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ရန် နေရာရွေးပါ"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"သင့်လျှို့ဝှက်ကီး ပြုလုပ်ခြင်း"</string>
<string name="save_your_password" msgid="6597736507991704307">"သင့်စကားဝှက် သိမ်းရန်"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"သင်၏ လက်မှတ်ထိုးဝင်သည့်အချက်အလက်ကို သိမ်းရန်"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"သင့်စကားဝှက်၊ လျှို့ဝှက်ကီးများ သိမ်းဆည်းရန်နှင့် နောက်တစ်ကြိမ်တွင် မြန်ဆန်စွာ လက်မှတ်ထိုးဝင်ရောက်ရန် မူရင်းစကားဝှက်မန်နေဂျာကို သတ်မှတ်ပါ။"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> တွင် လျှို့ဝှက်ကီး ပြုလုပ်မလား။"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"သင့်စကားဝှက်ကို <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> တွင် သိမ်းမလား။"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"သင်၏ လက်မှတ်ထိုးဝင်သည့်အချက်အလက်ကို <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> တွင် သိမ်းမလား။"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"လျှို့ဝှက်ကီး"</string>
<string name="password" msgid="6738570945182936667">"စကားဝှက်"</string>
<string name="sign_ins" msgid="4710739369149469208">"လက်မှတ်ထိုးဝင်မှုများ"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ဤနေရာတွင် လျှို့ဝှက်ကီးပြုလုပ်ရန်"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"စကားဝှက်ကို ဤနေရာတွင် သိမ်းရန်"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"လက်မှတ်ထိုးဝင်မှုကို ဤနေရာတွင် သိမ်းရန်"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"အခြားစက်တွင် လျှို့ဝှက်ကီးပြုလုပ်မလား။"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"သင်၏လက်မှတ်ထိုးဝင်မှု အားလုံးအတွက် <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> သုံးမလား။"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"သင်အလွယ်တကူ လက်မှတ်ထိုးဝင်နိုင်ရန် ဤစကားဝှက်မန်နေဂျာက စကားဝှက်နှင့် လျှို့ဝှက်ကီးများကို သိမ်းပါမည်။"</string>
<string name="set_as_default" msgid="4415328591568654603">"မူရင်းအဖြစ် သတ်မှတ်ရန်"</string>
<string name="use_once" msgid="9027366575315399714">"တစ်ကြိမ်သုံးရန်"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"စကားဝှက် <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ခု၊ လျှို့ဝှက်ကီး <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ခု"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"စကားဝှက် <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ခု"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"လျှို့ဝှက်ကီး <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ခု"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"လျှို့ဝှက်ကီး"</string>
<string name="another_device" msgid="5147276802037801217">"စက်နောက်တစ်ခု"</string>
<string name="other_password_manager" msgid="565790221427004141">"အခြားစကားဝှက်မန်နေဂျာများ"</string>
<string name="close_sheet" msgid="1393792015338908262">"စာမျက်နှာ ပိတ်ရန်"</string>
diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml
index 82854b82e555..f113f7291b93 100644
--- a/packages/CredentialManager/res/values-nb/strings.xml
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Legitimasjonslagring"</string>
<string name="string_cancel" msgid="6369133483981306063">"Avbryt"</string>
<string name="string_continue" msgid="1346732695941131882">"Fortsett"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Opprett på et annet sted"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Lagre på et annet sted"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Bruk en annen enhet"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Lagre på en annen enhet"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"En enkel og trygg påloggingsmåte"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Bruk fingeravtrykk, ansiktet eller en skjermlås til å logge på med en unik tilgangsnøkkel du verken kan glemme eller miste. Finn ut mer"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Velg hvor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Velg hvor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"opprette tilgangsnøklene dine"</string>
<string name="save_your_password" msgid="6597736507991704307">"lagre passordet ditt"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"lagre påloggingsinformasjonen din"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Angi et standardverktøy for passordlagring for å lagre passordene og tilgangsnøklene dine og logge på raskere neste gang."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vil du opprette en tilgangsnøkkel i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Vil du lagre passordet i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vil du lagre påloggingsinformasjonen i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"tilgangsnøkkel"</string>
<string name="password" msgid="6738570945182936667">"passord"</string>
<string name="sign_ins" msgid="4710739369149469208">"pålogginger"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Opprett en tilgangsnøkkel på"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Lagre passordet i"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Lagre påloggingen i"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vil du opprette en tilgangsnøkkel på en annen enhet?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vil du bruke <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for alle pålogginger?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Dette verktøyet for passordlagring lagrer passord og tilgangsnøkler, så det blir lett å logge på."</string>
<string name="set_as_default" msgid="4415328591568654603">"Angi som standard"</string>
<string name="use_once" msgid="9027366575315399714">"Bruk én gang"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passord, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> tilgangsnøkler"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passord"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> tilgangsnøkler"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Tilgangsnøkkel"</string>
<string name="another_device" msgid="5147276802037801217">"En annen enhet"</string>
<string name="other_password_manager" msgid="565790221427004141">"Andre løsninger for passordlagring"</string>
<string name="close_sheet" msgid="1393792015338908262">"Lukk arket"</string>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
index 23f4f430a799..cc8a38afb8bf 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"क्रिडेन्सियल म्यानेजर"</string>
<string name="string_cancel" msgid="6369133483981306063">"रद्द गर्नुहोस्"</string>
<string name="string_continue" msgid="1346732695941131882">"जारी राख्नुहोस्"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"अर्को ठाउँमा बनाउनुहोस्"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"अर्को ठाउँमा सेभ गर्नुहोस्"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"अर्को डिभाइस प्रयोग गर्नुहोस्"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"अर्को डिभाइसमा सेभ गर्नुहोस्"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"सुरक्षित तरिकाले साइन इन गर्ने सरल तरिका"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"नभुलिने वा चोरी नहुने खालको अद्वितीय पासकीका साथै आफ्ना फिंगरप्रिन्ट, अनुहार वा स्क्रिन लक प्रयोग गरी साइन इन गर्नुहोस्। थप जान्नुहोस्"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> सेभ गर्ने ठाउँ छनौट गर्नुहोस्"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> सेभ गर्ने ठाउँ छनौट गर्नुहोस्"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"आफ्ना पासकीहरू बाउनुहोस्"</string>
<string name="save_your_password" msgid="6597736507991704307">"आफ्नो पासवर्ड सेभ गर्नुहोस्"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"आफ्नो साइन इनसम्बन्धी जानकारी सेभ गर्नुहोस्"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"आफ्ना पासवर्ड तथा पासकीहरू सेभ गर्न र अर्को पटक अझ छिटो साइन इन गर्न डिफल्ट पासवर्ड म्यानेजर सेट गर्नुहोस्।"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मा पासकी बनाउने हो?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"तपाईंको पासवर्ड <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मा सेभ गर्ने हो?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"तपाईंको साइन इनसम्बन्धी जानकारी <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मा सेभ गर्ने हो?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"पासकी"</string>
<string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
<string name="sign_ins" msgid="4710739369149469208">"साइन इनसम्बन्धी जानकारी"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"यसमा पासकी बनाउनुहोस्:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"यसमा पासवर्ड सेभ गर्नुहोस्:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"यसमा साइन इनसम्बन्धी जानकारी सेभ गर्नुहोस्:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"अर्को डिभाइसमा पासकी बनाउने हो?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"तपाईंले साइन इन गर्ने सबै डिभाइसहरूमा <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> प्रयोग गर्ने हो?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"तपाईं सजिलै साइन इन गर्न सक्नुहोस् भन्नाका लागि यो पासवर्ड म्यानेजरले तपाईंका पासवर्ड तथा पासकीहरू सेभ गर्ने छ।"</string>
<string name="set_as_default" msgid="4415328591568654603">"डिफल्ट जानकारीका रूपमा सेट गर्नुहोस्"</string>
<string name="use_once" msgid="9027366575315399714">"एक पटक प्रयोग गर्नुहोस्"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> वटा पासवर्ड, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> वटा पासकी"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> वटा पासवर्ड"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> वटा पासकी"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"पासकी"</string>
<string name="another_device" msgid="5147276802037801217">"अर्को डिभाइस"</string>
<string name="other_password_manager" msgid="565790221427004141">"अन्य पासवर्ड म्यानेजरहरू"</string>
<string name="close_sheet" msgid="1393792015338908262">"पाना बन्द गर्नुहोस्"</string>
diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml
index c91a318e2073..72dff7370dc6 100644
--- a/packages/CredentialManager/res/values-nl/strings.xml
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Op een andere locatie opslaan"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Een ander apparaat gebruiken"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Opslaan op een ander apparaat"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Een makkelijke manier om beveiligd in te loggen"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gebruik je vingerafdruk, gezichtsvergrendeling of schermvergrendeling om in te loggen met een unieke toegangssleutel die je niet kunt vergeten en die anderen niet kunnen stelen. Meer informatie"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Een locatie kiezen voor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Een locatie kiezen voor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"je toegangssleutels maken"</string>
<string name="save_your_password" msgid="6597736507991704307">"je wachtwoord opslaan"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"je inloggegevens opslaan"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Stel een standaard wachtwoordmanager in om je wachtwoorden en toegangssleutels op te slaan zodat je de volgende keer sneller kunt inloggen."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Een toegangssleutel maken in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Je wachtwoord opslaan in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Je inloggegevens opslaan in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"toegangssleutel"</string>
<string name="password" msgid="6738570945182936667">"wachtwoord"</string>
<string name="sign_ins" msgid="4710739369149469208">"inloggegevens"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Toegangssleutel maken in"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Wachtwoord opslaan in"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Inloggegevens opslaan in"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Toegangssleutel maken op een ander apparaat?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> elke keer gebruiken als je inlogt?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Deze wachtwoordmanager slaat je wachtwoorden en toegangssleutels op zodat je makkelijk kunt inloggen."</string>
<string name="set_as_default" msgid="4415328591568654603">"Instellen als standaard"</string>
<string name="use_once" msgid="9027366575315399714">"Eén keer gebruiken"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wachtwoorden, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> toegangssleutels"</string>
diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml
index 838ddfe64a50..a1bbf1c2e9fb 100644
--- a/packages/CredentialManager/res/values-or/strings.xml
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"କ୍ରେଡେନସିଆଲ ମେନେଜର"</string>
<string name="string_cancel" msgid="6369133483981306063">"ବାତିଲ କରନ୍ତୁ"</string>
<string name="string_continue" msgid="1346732695941131882">"ଜାରି ରଖନ୍ତୁ"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"ଅନ୍ୟ ଏକ ସ୍ଥାନରେ ତିଆରି କରନ୍ତୁ"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"ଅନ୍ୟ ଏକ ସ୍ଥାନରେ ସେଭ କରନ୍ତୁ"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"ଅନ୍ୟ ଏହି ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"ଅନ୍ୟ ଏକ ଡିଭାଇସରେ ସେଭ କରନ୍ତୁ"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"ସୁରକ୍ଷିତ ଭାବେ ସାଇନ ଇନ କରିବାର ଏକ ସରଳ ଉପାୟ"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ଏକ ସ୍ୱତନ୍ତ୍ର ପାସକୀ ମାଧ୍ୟମରେ ସାଇନ ଇନ କରିବା ପାଇଁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ, ଫେସ କିମ୍ବା ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରନ୍ତୁ ଯାହାକୁ ଭୁଲି ପାରିବେ ନାହିଁ କିମ୍ବା ଚୋରି ହୋଇପାରିବ ନାହିଁ। ଅଧିକ ଜାଣନ୍ତୁ"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"କେଉଁଠି <xliff:g id="CREATETYPES">%1$s</xliff:g> କରିବେ, ତାହା ବାଛନ୍ତୁ"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"କେଉଁଠି <xliff:g id="CREATETYPES">%1$s</xliff:g> କରିବେ, ତାହା ବାଛନ୍ତୁ"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ଆପଣଙ୍କ ପାସକୀଗୁଡ଼ିକ ତିଆରି କରନ୍ତୁ"</string>
<string name="save_your_password" msgid="6597736507991704307">"ଆପଣଙ୍କ ପାସୱାର୍ଡ ସେଭ କରନ୍ତୁ"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ଆପଣଙ୍କ ସାଇନ-ଇନ ସୂଚନା ସେଭ କରନ୍ତୁ"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"ଆପଣଙ୍କ ପାସୱାର୍ଡ ଓ ପାସକୀଗୁଡ଼ିକୁ ସେଭ କରିବା ପାଇଁ ଏକ ଡିଫଲ୍ଟ Password Manager ସେଟ କରନ୍ତୁ ଏବଂ ପରବର୍ତ୍ତୀ ଥର ଶୀଘ୍ର ସାଇନ ଇନ କରନ୍ତୁ।"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ରେ ଏକ ପାସକୀ ତିଆରି କରିବେ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"ଆପଣଙ୍କ ପାସୱାର୍ଡକୁ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ରେ ସେଭ କରିବେ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ଆପଣଙ୍କ ସାଇନ-ଇନ ସୂଚନାକୁ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ରେ ସେଭ କରିବେ?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"ପାସକୀ"</string>
<string name="password" msgid="6738570945182936667">"ପାସୱାର୍ଡ"</string>
<string name="sign_ins" msgid="4710739369149469208">"ସାଇନ-ଇନ"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ଏଥିରେ ପାସକୀ ତିଆରି କରନ୍ତୁ"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"ଏଥିରେ ପାସୱାର୍ଡ ସେଭ କରନ୍ତୁ"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ଏଥିରେ ସାଇନ-ଇନ ସେଭ କରନ୍ତୁ"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"ଅନ୍ୟ ଏକ ଡିଭାଇସରେ ପାସକୀ ତିଆରି କରିବେ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ଆପଣଙ୍କ ସମସ୍ତ ସାଇନ-ଇନ ପାଇଁ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବେ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"ଏହି Password Manager ସହଜରେ ସାଇନ ଇନ କରିବାରେ ଆପଣଙ୍କୁ ସାହାଯ୍ୟ କରିବା ପାଇଁ ଆପଣଙ୍କ ପାସୱାର୍ଡ ଏବଂ ପାସକୀଗୁଡ଼ିକୁ ଷ୍ଟୋର କରିବ।"</string>
<string name="set_as_default" msgid="4415328591568654603">"ଡିଫଲ୍ଟ ଭାବେ ସେଟ କରନ୍ତୁ"</string>
<string name="use_once" msgid="9027366575315399714">"ଥରେ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ଟି ପାସୱାର୍ଡ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>ଟି ପାସକୀ"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ଟି ପାସୱାର୍ଡ"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>ଟି ପାସକୀ"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"ପାସକୀ"</string>
<string name="another_device" msgid="5147276802037801217">"ଅନ୍ୟ ଏକ ଡିଭାଇସ"</string>
<string name="other_password_manager" msgid="565790221427004141">"ଅନ୍ୟ Password Manager"</string>
<string name="close_sheet" msgid="1393792015338908262">"ସିଟ ବନ୍ଦ କରନ୍ତୁ"</string>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
index 74b2ab123ec0..36989c670bfe 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"ਕ੍ਰੀਡੈਂਸ਼ੀਅਲ ਪ੍ਰਬੰਧਕ"</string>
<string name="string_cancel" msgid="6369133483981306063">"ਰੱਦ ਕਰੋ"</string>
<string name="string_continue" msgid="1346732695941131882">"ਜਾਰੀ ਰੱਖੋ"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"ਕਿਸੇ ਹੋਰ ਥਾਂ \'ਤੇ ਬਣਾਓ"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"ਕਿਸੇ ਹੋਰ ਥਾਂ \'ਤੇ ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"ਕੋਈ ਹੋਰ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ \'ਤੇ ਰੱਖਿਅਤ ਕਰੋ"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਦਾ ਆਸਾਨ ਤਰੀਕਾ"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ਵਿਲੱਖਣ ਪਾਸਕੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਵਾਸਤੇ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ, ਚਿਹਰੇ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ ਜਿਸਨੂੰ ਭੁੱਲਿਆ ਜਾਂ ਚੋਰੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਹੋਰ ਜਾਣੋ"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ਲਈ ਕੋਈ ਥਾਂ ਚੁਣੋ"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ਲਈ ਕੋਈ ਥਾਂ ਚੁਣੋ"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ਆਪਣੀਆਂ ਪਾਸਕੀਆਂ ਬਣਾਓ"</string>
<string name="save_your_password" msgid="6597736507991704307">"ਆਪਣਾ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ਆਪਣੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰੋ"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"ਆਪਣੇ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਾਸਕੀਆਂ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਲਈ ਕੋਈ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ ਸੈੱਟ ਕਰੋ ਅਤੇ ਅਗਲੀ ਵਾਰ ਤੇਜ਼ੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰੋ।"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"ਕੀ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਵਿੱਚ ਪਾਸਕੀ ਨੂੰ ਬਣਾਉਣਾ ਹੈ?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"ਕੀ ਆਪਣੇ ਪਾਸਵਰਡ ਨੂੰ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ਕੀ ਆਪਣੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਨੂੰ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"ਪਾਸਕੀ"</string>
<string name="password" msgid="6738570945182936667">"ਪਾਸਵਰਡ"</string>
<string name="sign_ins" msgid="4710739369149469208">"ਸਾਈਨ-ਇਨਾਂ ਦੀ ਜਾਣਕਾਰੀ"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"ਇਸ ਵਿੱਚ ਪਾਸਕੀ ਬਣਾਓ"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"ਇਸ \'ਤੇ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਕਰੋ"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"ਇਸ \'ਤੇ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰੋ"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"ਕੀ ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ ਵਿੱਚ ਕੋਈ ਪਾਸਕੀ ਬਣਾਉਣੀ ਹੈ?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ਕੀ ਆਪਣੇ ਸਾਰੇ ਸਾਈਨ-ਇਨਾਂ ਲਈ<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"ਇਹ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ ਤੁਹਾਡੀ ਆਸਾਨੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਾਸਕੀਆਂ ਨੂੰ ਸਟੋਰ ਕਰੇਗਾ।"</string>
<string name="set_as_default" msgid="4415328591568654603">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਜੋਂ ਸੈੱਟ ਕਰੋ"</string>
<string name="use_once" msgid="9027366575315399714">"ਇੱਕ ਵਾਰ ਵਰਤੋ"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ਪਾਸਵਰਡ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ਪਾਸਕੀਆਂ"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ਪਾਸਵਰਡ"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ਪਾਸਕੀਆਂ"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"ਪਾਸਕੀ"</string>
<string name="another_device" msgid="5147276802037801217">"ਹੋਰ ਡੀਵਾਈਸ"</string>
<string name="other_password_manager" msgid="565790221427004141">"ਹੋਰ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ"</string>
<string name="close_sheet" msgid="1393792015338908262">"ਸ਼ੀਟ ਬੰਦ ਕਰੋ"</string>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
index af6bc9d22fa8..462ded06e825 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Menedżer danych logowania"</string>
<string name="string_cancel" msgid="6369133483981306063">"Anuluj"</string>
<string name="string_continue" msgid="1346732695941131882">"Dalej"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Utwórz w innym miejscu"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Zapisz w innym miejscu"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Użyj innego urządzenia"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Zapisz na innym urządzeniu"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Prosty sposób na bezpieczne logowanie"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Używaj odcisku palca, rozpoznawania twarzy lub blokady ekranu, aby logować się z wykorzystaniem unikalnego klucza, którego nie można zapomnieć ani utracić w wyniku kradzieży. Więcej informacji"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Wybierz, gdzie chcesz <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Wybierz, gdzie chcesz <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"tworzyć klucze"</string>
<string name="save_your_password" msgid="6597736507991704307">"zapisać hasło"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"zapisać dane logowania"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Ustaw domyślny menedżer haseł, aby zapisywać swoje hasła oraz klucze dostępu i aby logować się szybciej w przyszłości."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Utworzyć klucz w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Zapisać hasło w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Zapisać dane logowania w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"klucz"</string>
<string name="password" msgid="6738570945182936667">"hasło"</string>
<string name="sign_ins" msgid="4710739369149469208">"dane logowania"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Utwórz klucz w usłudze"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Zapisz hasło w usłudze"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Zapisz dane logowania w usłudze"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Utworzyć klucz na innym urządzeniu?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Używać usługi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> w przypadku wszystkich danych logowania?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Menedżer haseł będzie zapisywał Twoje hasła i klucze, aby ułatwić Ci logowanie."</string>
<string name="set_as_default" msgid="4415328591568654603">"Ustaw jako domyślną"</string>
<string name="use_once" msgid="9027366575315399714">"Użyj raz"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Hasła: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, klucze: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Hasła: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Klucze: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Klucz"</string>
<string name="another_device" msgid="5147276802037801217">"Inne urządzenie"</string>
<string name="other_password_manager" msgid="565790221427004141">"Inne menedżery haseł"</string>
<string name="close_sheet" msgid="1393792015338908262">"Zamknij arkusz"</string>
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index d950bb45366e..945adc2986ee 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Salvar em outro lugar"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Salvar em outro dispositivo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Uma maneira simples de fazer login com segurança"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use a impressão digital, o reconhecimento facial ou um bloqueio de tela para fazer login com uma única chave de acesso que não pode ser esquecida ou perdida. Saiba mais"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"crie suas chaves de acesso"</string>
<string name="save_your_password" msgid="6597736507991704307">"salvar sua senha"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"salvar suas informações de login"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Defina um gerenciador de senhas padrão para salvar suas senhas e chaves de acesso e fazer login mais rápido na próxima vez."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Criar uma chave de acesso em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Salvar sua senha em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Salvar suas informações de login em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"senha"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Criar chave de acesso em"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Salvar senha em"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Salvar informações de login em"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Criar uma chave de acesso em outro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus logins?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gerenciador de senhas vai armazenar suas senhas e chaves de acesso para facilitar o processo de login."</string>
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index c46143cbae51..93a7a5f22ad3 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -8,8 +8,14 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar noutro lugar"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar noutro dispositivo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Uma forma simples de iniciar sessão em segurança"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use a sua impressão digital, rosto ou bloqueio de ecrã para iniciar sessão com uma chave de acesso única que não pode ser esquecida nem perdida. Saiba mais"</string>
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
<string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde quer guardar <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="create_your_passkeys" msgid="8901224153607590596">"criar as suas chaves de acesso"</string>
<string name="save_your_password" msgid="6597736507991704307">"guardar a sua palavra-passe"</string>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index d950bb45366e..945adc2986ee 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Salvar em outro lugar"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Salvar em outro dispositivo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Uma maneira simples de fazer login com segurança"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use a impressão digital, o reconhecimento facial ou um bloqueio de tela para fazer login com uma única chave de acesso que não pode ser esquecida ou perdida. Saiba mais"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"crie suas chaves de acesso"</string>
<string name="save_your_password" msgid="6597736507991704307">"salvar sua senha"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"salvar suas informações de login"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Defina um gerenciador de senhas padrão para salvar suas senhas e chaves de acesso e fazer login mais rápido na próxima vez."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Criar uma chave de acesso em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Salvar sua senha em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Salvar suas informações de login em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"senha"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Criar chave de acesso em"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Salvar senha em"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Salvar informações de login em"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Criar uma chave de acesso em outro dispositivo?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus logins?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gerenciador de senhas vai armazenar suas senhas e chaves de acesso para facilitar o processo de login."</string>
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
index 6947281390f0..da7ec1a98b6d 100644
--- a/packages/CredentialManager/res/values-ro/strings.xml
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Manager de date de conectare"</string>
<string name="string_cancel" msgid="6369133483981306063">"Anulează"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuă"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Creează în alt loc"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Salvează în alt loc"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Folosește alt dispozitiv"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Salvează pe alt dispozitiv"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un mod simplu de a te conecta în siguranță"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Folosește-ți amprenta, fața sau blocarea ecranului ca să te conectezi cu o cheie de acces unică, pe care nu o poți uita și care nu poate fi furată. Află mai multe"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Alege unde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Alege unde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"creează cheile de acces"</string>
<string name="save_your_password" msgid="6597736507991704307">"salvează parola"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"salvează informațiile de conectare"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Setează un manager de parole implicit pentru a salva parolele și cheile de acces și a te conecta mai rapid data viitoare."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Creezi o cheie de acces în <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Salvezi parola în <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Salvezi informațiile de conectare în <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"cheie de acces"</string>
<string name="password" msgid="6738570945182936667">"parolă"</string>
<string name="sign_ins" msgid="4710739369149469208">"date de conectare"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Creează o cheie de acces în"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Salvează parola în"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Salvează datele de conectare în"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Creezi o cheie de acces în alt dispozitiv?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Folosești <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pentru toate conectările?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Managerul de parole îți va stoca parolele și cheile de acces, pentru a te ajuta să te conectezi cu ușurință."</string>
<string name="set_as_default" msgid="4415328591568654603">"Setează ca prestabilite"</string>
<string name="use_once" msgid="9027366575315399714">"Folosește o dată"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parole, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chei de acces"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parole"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chei de acces"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Cheie de acces"</string>
<string name="another_device" msgid="5147276802037801217">"Alt dispozitiv"</string>
<string name="other_password_manager" msgid="565790221427004141">"Alți manageri de parole"</string>
<string name="close_sheet" msgid="1393792015338908262">"Închide foaia"</string>
diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml
index dcc643eee7cd..7dc51a2d1a7a 100644
--- a/packages/CredentialManager/res/values-ru/strings.xml
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Сохранить в другом месте"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Использовать другое устройство"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Сохранить на другом устройстве"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Простой и безопасный способ входа"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"С уникальным ключом доступа, который невозможно украсть или забыть, вы можете подтверждать свою личность по отпечатку пальца, с помощью фейсконтроля или блокировки экрана. Подробнее…"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Выберите, где <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Выберите, где <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"создать ключи доступа"</string>
<string name="save_your_password" msgid="6597736507991704307">"сохранить пароль"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"сохранить данные для входа"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Задайте менеджер паролей по умолчанию, чтобы сохранять пароли и ключи доступа и быстро выполнять вход."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Создать ключ доступа в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Сохранить пароль в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Сохранить учетные данные в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"ключ доступа"</string>
<string name="password" msgid="6738570945182936667">"пароль"</string>
<string name="sign_ins" msgid="4710739369149469208">"входы"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Выберите, где создать ключ доступа"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Выберите, где сохранить пароль"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Выберите, где сохранить учетные данные"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Создать ключ доступа на другом устройстве?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Всегда входить с помощью приложения \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"В этом менеджере паролей можно сохранять учетные данные, например ключи доступа, чтобы потом использовать их."</string>
<string name="set_as_default" msgid="4415328591568654603">"Использовать по умолчанию"</string>
<string name="use_once" msgid="9027366575315399714">"Использовать один раз"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Пароли (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>) и ключи доступа (<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>)"</string>
diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml
index bf885a987cba..fd94e5a3f9ea 100644
--- a/packages/CredentialManager/res/values-si/strings.xml
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"අක්තපත්‍ර කළමනාකරු"</string>
<string name="string_cancel" msgid="6369133483981306063">"අවලංගු කරන්න"</string>
<string name="string_continue" msgid="1346732695941131882">"ඉදිරියට යන්න"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"වෙනත් ස්ථානයක තනන්න"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"වෙනත් ස්ථානයකට සුරකින්න"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"වෙනත් උපාංගයක් භාවිතා කරන්න"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"වෙනත් උපාංගයකට සුරකින්න"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"සුරක්ෂිතව පුරනය වීමට සරල ක්‍රමයක්"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"අමතක කළ නොහැකි හෝ සොරකම් කළ නොහැකි අනන්‍ය මුරයතුරක් සමග පුරනය වීමට ඔබේ ඇඟිලි සලකුණ, මුහුණ හෝ තිර අගුල භාවිතා කරන්න. තව දැන ගන්න⁠"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> කොතැනක ද යන්න තෝරා ගන්න"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> කොතැනක ද යන්න තෝරා ගන්න"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ඔබේ මුරයතුරු තනන්න"</string>
<string name="save_your_password" msgid="6597736507991704307">"ඔබේ මුරපදය සුරකින්න"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ඔබේ පුරනය වීමේ තතු සුරකින්න"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"ඔබේ මුරපද සහ මුරයතුරු සුරැකීමට පෙරනිමි මුරපද කළමනාකරු සකසන්න සහ මීළඟ වතාවේ වේගයෙන් පුරනය වන්න."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> තුළ මුරයතුරක් තනන්න ද?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"ඔබේ මුරපදය <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> වෙත සුරකින්න ද?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ඔබේ පුරනය වීමේ තතු <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> වෙත සුරකින්න ද?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"මුරයතුර"</string>
<string name="password" msgid="6738570945182936667">"මුරපදය"</string>
<string name="sign_ins" msgid="4710739369149469208">"පුරනය වීම්"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"මුරයතුර තනන්නේ"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"මෙයට මුරපදය සුරකින්න"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"පුරනය වීම සුරකින්නේ"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"වෙනත් උපාංගයක මුරයතුරක් තනන්න ද?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ඔබේ සියලු පුරනය වීම් සඳහා <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> භාවිතා කරන්න ද?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"මෙම මුරපද කළමනාකරු ඔබට පහසුවෙන් පුරනය වීමට උදවු කිරීම සඳහා ඔබේ මුරපද සහ මුරයතුරු ගබඩා කරනු ඇත."</string>
<string name="set_as_default" msgid="4415328591568654603">"පෙරනිමි ලෙස සකසන්න"</string>
<string name="use_once" msgid="9027366575315399714">"වරක් භාවිතා කරන්න"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"මුරපද <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ක්, මුරයතුරු <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>ක්"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"මුරපද <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ක්"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"මුරයතුරු <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>ක්"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"මුරයතුර"</string>
<string name="another_device" msgid="5147276802037801217">"වෙනත් උපාංගයක්"</string>
<string name="other_password_manager" msgid="565790221427004141">"වෙනත් මුරපද කළමනාකරුවන්"</string>
<string name="close_sheet" msgid="1393792015338908262">"පත්‍රය වසන්න"</string>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
index 1c73c57d0421..cd8136139089 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -8,8 +8,14 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Uložiť inde"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Použiť iné zariadenie"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Uložiť do iného zariadenia"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednoduchý spôsob bezpečného prihlasovania"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Použite odtlačok prsta, tvár alebo zámku obrazovky a prihláste sa jedinečným prístupovým kľúčom, ktorý sa nedá zabudnúť ani ukradnúť. Ďalšie informácie"</string>
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
<string name="choose_provider_title" msgid="7245243990139698508">"Vyberte, kam <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="create_your_passkeys" msgid="8901224153607590596">"vytvoriť prístupové kľúče"</string>
<string name="save_your_password" msgid="6597736507991704307">"uložiť heslo"</string>
diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml
index 969f29032837..c769e19b3692 100644
--- a/packages/CredentialManager/res/values-sl/strings.xml
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Shranjevanje na drugo mesto"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Uporabi drugo napravo"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Shrani v drugo napravo"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Preprost način za varno prijavo"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Če se želite prijaviti z enoličnim ključem za dostop, ki ga ni mogoče pozabiti ali ukrasti, uporabite prstni odtis, obraz ali nastavljeni način za odklepanje zaslona. Več o tem"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Izberite mesto za <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Izberite mesto za <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"ustvarjanje ključev za dostop"</string>
<string name="save_your_password" msgid="6597736507991704307">"shranjevanje gesla"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"shranjevanje podatkov za prijavo"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Nastavite privzetega upravitelja gesel za shranjevanje gesel in ključev za dostop, da se boste naslednjič lahko hitreje prijavili."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Želite ustvariti ključ za dostop pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Želite shraniti geslo pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Želite shraniti podatke za prijavo pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"ključ za dostop"</string>
<string name="password" msgid="6738570945182936667">"geslo"</string>
<string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Ustvarjanje ključa za dostop v"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Shranjevanje gesla v"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Shranjevanje podatkov za prijavo v"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Želite ustvariti ključ za dostop v drugi napravi?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite za vse prijave uporabiti »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"V tem upravitelju gesel bodo shranjeni gesla in ključi za dostop, kar vam bo olajšalo prijavo."</string>
<string name="set_as_default" msgid="4415328591568654603">"Nastavi kot privzeto"</string>
<string name="use_once" msgid="9027366575315399714">"Uporabi enkrat"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Št. gesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, št. ključev za dostop: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
index bce068309839..7e656d638386 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Menaxheri i kredencialeve"</string>
<string name="string_cancel" msgid="6369133483981306063">"Anulo"</string>
<string name="string_continue" msgid="1346732695941131882">"Vazhdo"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Krijo në një vend tjetër"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Ruaj në një vend tjetër"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Përdor një pajisje tjetër"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Ruaj në një pajisje tjetër"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Një mënyrë e thjeshtë për t\'u identifikuar në mënyrë të sigurt"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Përdor gjurmën e gishtit, fytyrën ose kyçjen e ekranit për t\'u identifikuar me një çelës unik kalimi i cili nuk mund të harrohet ose të vidhet. Mëso më shumë"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Zgjidh se ku të <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Zgjidh se ku të <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"do t\'i krijosh çelësat e tu të kalimit"</string>
<string name="save_your_password" msgid="6597736507991704307">"ruaj fjalëkalimin"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"ruaj informacionet e tua të identifikimit"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Cakto një menaxher të parazgjedhur të fjalëkalimeve për të ruajtur fjalëkalimet dhe çelësat e kalimit dhe për t\'u identifikuar më shpejt herën tjetër."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Të krijohet një çelës kalimi në <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Të ruhet fjalëkalimi në <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Të ruhen informacionet e tua të identifikimit në <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"çelësi i kalimit"</string>
<string name="password" msgid="6738570945182936667">"fjalëkalimi"</string>
<string name="sign_ins" msgid="4710739369149469208">"identifikimet"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Krijo çelësin e kalimit te"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Ruaj fjalëkalimin në"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Ruaj identifikimin në"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Të krijohet një çelës kalimi në një pajisje tjetër?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Të përdoret <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> për të gjitha identifikimet?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Ky menaxher i fjalëkalimeve do të ruajë fjalëkalimet dhe çelësat e kalimit për të të ndihmuar të identifikohesh me lehtësi."</string>
<string name="set_as_default" msgid="4415328591568654603">"Cakto si parazgjedhje"</string>
<string name="use_once" msgid="9027366575315399714">"Përdor një herë"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> fjalëkalime, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> çelësa kalimi"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> fjalëkalime"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> çelësa kalimi"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Çelësi i kalimit"</string>
<string name="another_device" msgid="5147276802037801217">"Një pajisje tjetër"</string>
<string name="other_password_manager" msgid="565790221427004141">"Menaxherët e tjerë të fjalëkalimeve"</string>
<string name="close_sheet" msgid="1393792015338908262">"Mbyll fletën"</string>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
index 6a5235c79d56..cfb6c055e0c1 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Менаџер акредитива"</string>
<string name="string_cancel" msgid="6369133483981306063">"Откажи"</string>
<string name="string_continue" msgid="1346732695941131882">"Настави"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Направи на другом месту"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Сачувај на другом месту"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Користи други уређај"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Сачувај на други уређај"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Једноставан начин да се безбедно пријављујете"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Користите отисак прста, закључавање лицем или закључавање екрана да бисте се пријавили помоћу јединственог приступног кода који не може да се заборави или украде. Сазнајте више"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Одаберите локацију за: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Одаберите локацију за: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"направите приступне кодове"</string>
<string name="save_your_password" msgid="6597736507991704307">"сачувајте лозинку"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"сачувајте податке о пријављивању"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Подесите подразумевани менаџер лозинки да бисте сачували лозинке и приступне кодове и следећи пут се пријавили брже."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Желите да направите приступни кôд код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Желите да сачувате лозинку код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Желите да сачувате податке о пријављивању код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"приступни кôд"</string>
<string name="password" msgid="6738570945182936667">"лозинка"</string>
<string name="sign_ins" msgid="4710739369149469208">"пријављивања"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Направите приступни кôд у:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Сачувајте лозинку на:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Сачувајте податке о пријављивању на:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Желите да направите приступни кôд на другом уређају?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Желите да за сва пријављивања користите: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Овај менаџер лозинки ће чувати лозинке и приступне кодове да бисте се лако пријављивали."</string>
<string name="set_as_default" msgid="4415328591568654603">"Подеси као подразумевано"</string>
<string name="use_once" msgid="9027366575315399714">"Користи једном"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Лозинки: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, приступних кодова:<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Лозинки: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Приступних кодова: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Приступни кôд"</string>
<string name="another_device" msgid="5147276802037801217">"Други уређај"</string>
<string name="other_password_manager" msgid="565790221427004141">"Други менаџери лозинки"</string>
<string name="close_sheet" msgid="1393792015338908262">"Затворите табелу"</string>
diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml
index a4fffb979b8f..842d7876f5da 100644
--- a/packages/CredentialManager/res/values-sv/strings.xml
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"Spara på en annan plats"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Använd en annan enhet"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Spara på en annan enhet"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Ett enkelt sätt att logga in säkert på"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Använd ditt fingeravtryck, ansikte eller skärmlås om du vill logga in med en unik nyckel som inte kan glömmas bort eller bli stulen. Läs mer"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Välj var du <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Välj var du <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"skapa nycklar"</string>
<string name="save_your_password" msgid="6597736507991704307">"spara lösenordet"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"spara inloggningsuppgifterna"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Ställ in vilken lösenordshanterare som ska användas som standard om du vill spara lösenord, nycklar och inloggningsuppgifter snabbare nästa gång."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vill du skapa en nyckel i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Vill du spara ditt lösenord i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vill du spara dina inloggningsuppgifter i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"nyckel"</string>
<string name="password" msgid="6738570945182936667">"lösenord"</string>
<string name="sign_ins" msgid="4710739369149469208">"inloggningar"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Skapa nyckel i"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Spara lösenordet i"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Spara inloggningen i"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Vill du skapa en nyckel på en annan enhet?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Vill du använda <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> för alla dina inloggningar?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Den här lösenordshanteraren sparar dina lösenord och nycklar för att underlätta inloggning."</string>
<string name="set_as_default" msgid="4415328591568654603">"Ange som standard"</string>
<string name="use_once" msgid="9027366575315399714">"Använd en gång"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> lösenord, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> nycklar"</string>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
index bfd10747554c..3eb74328b639 100644
--- a/packages/CredentialManager/res/values-sw/strings.xml
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Kidhibiti cha Vitambulisho"</string>
<string name="string_cancel" msgid="6369133483981306063">"Ghairi"</string>
<string name="string_continue" msgid="1346732695941131882">"Endelea"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Unda katika sehemu nyingine"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Hifadhi sehemu nyingine"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Tumia kifaa kingine"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Hifadhi kwenye kifaa kingine"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Njia rahisi ya kuingia katika akaunti kwa usalama"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Tumia alama ya vidole, uso au kipengele cha kufunga skrini ili uingie katika kaunti kwa kutumia nenosiri la kipekee ambalo haliwezi kusahaulika au kuibiwa. Pata maelezo zaidi"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Chagua mahali pa <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Chagua mahali pa <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"unda funguo zako za siri"</string>
<string name="save_your_password" msgid="6597736507991704307">"hifadhi nenosiri lako"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"hifadhi maelezo yako ya kuingia katika akaunti"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Weka kidhibiti chaguomsingi cha manenosiri ili uhifadhi manenosiri na funguo zako za siri na uingie katika akaunti kwa haraka wakati mwingine."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Ungependa kuunda ufunguo wa siri katika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Ungependa kuhifadhi nenosiri lako kwenye <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Ungependa kuhifadhi maelezo yako ya kuingia katika akaunti kwenye <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"ufunguo wa siri"</string>
<string name="password" msgid="6738570945182936667">"nenosiri"</string>
<string name="sign_ins" msgid="4710739369149469208">"michakato ya kuingia katika akaunti"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Unda ufunguo wa siri kwenye"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Hifadhi nenosiri kwenye"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Hifadhi kitambulisho cha kuingia katika akaunti kwenye"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Ungependa kuunda ufunguo wa siri kwenye kifaa kingine?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Ungependa kutumia <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kwa ajili ya michakato yako yote ya kuingia katika akaunti?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Kidhibiti hiki cha manenosiri kitahifadhi manenosiri na funguo zako za siri ili kukusaidia uingie katika akaunti kwa urahisi."</string>
<string name="set_as_default" msgid="4415328591568654603">"Weka iwe chaguomsingi"</string>
<string name="use_once" msgid="9027366575315399714">"Tumia mara moja"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Manenosiri <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, funguo <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> za siri"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Manenosiri <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Funguo <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> za siri"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Ufunguo wa siri"</string>
<string name="another_device" msgid="5147276802037801217">"Kifaa kingine"</string>
<string name="other_password_manager" msgid="565790221427004141">"Vidhibiti vinginevyo vya manenosiri"</string>
<string name="close_sheet" msgid="1393792015338908262">"Funga laha"</string>
diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml
index 10c52594c7d3..2d7d84ef9e54 100644
--- a/packages/CredentialManager/res/values-ta/strings.xml
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"அனுமதிச் சான்று நிர்வாகி"</string>
<string name="string_cancel" msgid="6369133483981306063">"ரத்துசெய்"</string>
<string name="string_continue" msgid="1346732695941131882">"தொடர்க"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"மற்றொரு இடத்தில் உருவாக்கவும்"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"மற்றொரு இடத்தில் சேமிக்கவும்"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"மற்றொரு சாதனத்தைப் பயன்படுத்தவும்"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"வேறொரு சாதனத்தில் சேமியுங்கள்"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"பாதுகாப்பாக உள்நுழைவதற்கான எளிய வழி"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"தனித்துவமான கடவுக்குறியீடு (மறக்காதவை அல்லது திருடமுடியாதவை) மூலம் உள்நுழைய, உங்கள் கைரேகை, முகம் அல்லது திரைப்பூட்டைப் பயன்படுத்தி உள்நுழையவும். மேலும் அறிக"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> எங்கே காட்டப்பட வேண்டும் என்பதைத் தேர்வுசெய்தல்"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> எங்கே காட்டப்பட வேண்டும் என்பதைத் தேர்வுசெய்தல்"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"உங்கள் கடவுச்சாவிகளை உருவாக்குங்கள்"</string>
<string name="save_your_password" msgid="6597736507991704307">"உங்கள் கடவுச்சொல்லைச் சேமிக்கவும்"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"உங்கள் உள்நுழைவு தகவலைச் சேமிக்கவும்"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"கடவுச்சொற்கள் &amp; கடவுச்சாவிகளைச் சேமிக்கவும் அடுத்தமுறை விரைவாக உள்நுழையவும் ஓர் இயல்பான Password Managerரை அமையுங்கள்."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ல் கடவுக்குறியீட்டை உருவாக்க வேண்டுமா?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"உங்கள் கடவுச்சொல்லை <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ல் சேமிக்க வேண்டுமா?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"உங்கள் உள்நுழைவுத் தகவலை <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ல் சேமிக்க வேண்டுமா?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"கடவுக்குறியீடு"</string>
<string name="password" msgid="6738570945182936667">"கடவுச்சொல்"</string>
<string name="sign_ins" msgid="4710739369149469208">"உள்நுழைவுகள்"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"இதில் கடவுச்சாவியை உருவாக்குங்கள்:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"கடவுச்சொல்லை இதில் சேமியுங்கள்:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"உள்நுழைவுத் தகவலை இதில் சேமியுங்கள்:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"வேறொரு சாதனத்தில் கடவுச்சாவியை உருவாக்கவா?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"உங்கள் அனைத்து உள்நுழைவுகளுக்கும் <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ஐப் பயன்படுத்தவா?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"எளிதில் உள்நுழைவதற்கு உதவும் வகையில் இந்த Password Manager உங்கள் கடவுச்சொற்களையும் கடவுச்சாவிகளையும் சேமிக்கும்."</string>
<string name="set_as_default" msgid="4415328591568654603">"இயல்பானதாக அமை"</string>
<string name="use_once" msgid="9027366575315399714">"ஒருமுறை பயன்படுத்தவும்"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> கடவுச்சொற்கள், <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> கடவுக்குறியீடுகள்"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> கடவுச்சொற்கள்"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> கடவுக்குறியீடுகள்"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"கடவுக்குறியீடு"</string>
<string name="another_device" msgid="5147276802037801217">"மற்றொரு சாதனம்"</string>
<string name="other_password_manager" msgid="565790221427004141">"பிற கடவுச்சொல் நிர்வாகிகள்"</string>
<string name="close_sheet" msgid="1393792015338908262">"ஷீட்டை மூடும்"</string>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
index f7617b3e34dd..664252d5a576 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"డాక్యుమెంట్ ప్రూఫ్ మేనేజర్"</string>
<string name="string_cancel" msgid="6369133483981306063">"రద్దు చేయండి"</string>
<string name="string_continue" msgid="1346732695941131882">"కొనసాగించండి"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"మరొక స్థలంలో క్రియేట్ చేయండి"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"మరొక స్థలంలో సేవ్ చేయండి"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"మరొక పరికరాన్ని ఉపయోగించండి"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"మరొక పరికరంలో సేవ్ చేయండి"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"సురక్షితంగా సైన్ ఇన్ చేయడానికి సులభమైన మార్గం"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"మర్చిపోలేని లేదా దొంగిలించలేని ప్రత్యేకమైన పాస్-కీతో సైన్ ఇన్ చేయడానికి మీ వేలిముద్ర, ముఖం లేదా స్క్రీన్ లాక్‌ను ఉపయోగించండి. మరింత తెలుసుకోండి"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"ఎక్కడ <xliff:g id="CREATETYPES">%1$s</xliff:g> చేయాలో ఎంచుకోండి"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"ఎక్కడ <xliff:g id="CREATETYPES">%1$s</xliff:g> చేయాలో ఎంచుకోండి"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"మీ పాస్-కీలను క్రియేట్ చేయండి"</string>
<string name="save_your_password" msgid="6597736507991704307">"మీ పాస్‌వర్డ్‌ను సేవ్ చేయండి"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"మీ సైన్ ఇన్ సమాచారాన్ని సేవ్ చేయండి"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"మీ పాస్‌వర్డ్‌లు, పాస్‌కీలను సేవ్ చేయడానికి ఆటోమేటిక్ సెట్టింగ్ పాస్‌వర్డ్ మేనేజర్‌ను సెట్ చేయండి, తదుపరిసారి వేగంగా సైన్ ఇన్ చేయండి."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>లో పాస్-కీని క్రియేట్ చేయాలా?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"మీ పాస్‌వర్డ్‌ను <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>కు సేవ్ చేయాలా?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"మీ సైన్ ఇన్ సమాచారాన్ని <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>కు సేవ్ చేయాలా?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"పాస్-కీ"</string>
<string name="password" msgid="6738570945182936667">"పాస్‌వర్డ్"</string>
<string name="sign_ins" msgid="4710739369149469208">"సైన్‌ ఇన్‌లు"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"వీటిలో పాస్-కీని క్రియేట్ చేయండి"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"పాస్‌వర్డ్‌ను దీనికి సేవ్ చేయండి"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"సైన్ ఇన్‌ను దీనికి సేవ్ చేయండి"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"మరొక పరికరంలో పాస్-కీని క్రియేట్ చేయాలా?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"మీ అన్ని సైన్-ఇన్ వివరాల కోసం <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ను ఉపయోగించాలా?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"మీరు సులభంగా సైన్ ఇన్ చేయడంలో సహాయపడటానికి ఈ పాస్‌వర్డ్ మేనేజర్ మీ పాస్‌వర్డ్‌లు, పాస్-కీలను స్టోర్ చేస్తుంది."</string>
<string name="set_as_default" msgid="4415328591568654603">"ఆటోమేటిక్ సెట్టింగ్‌గా సెట్ చేయండి"</string>
<string name="use_once" msgid="9027366575315399714">"ఒకసారి ఉపయోగించండి"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> పాస్‌వర్డ్‌లు, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> పాస్-కీలు"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> పాస్‌వర్డ్‌లు"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> పాస్-కీలు"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"పాస్-కీ"</string>
<string name="another_device" msgid="5147276802037801217">"మరొక పరికరం"</string>
<string name="other_password_manager" msgid="565790221427004141">"ఇతర పాస్‌వర్డ్ మేనేజర్‌లు"</string>
<string name="close_sheet" msgid="1393792015338908262">"షీట్‌ను మూసివేయండి"</string>
diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
index d70e94ad0425..106c456ab650 100644
--- a/packages/CredentialManager/res/values-th/strings.xml
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"บันทึกลงในตำแหน่งอื่น"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"ใช้อุปกรณ์อื่น"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"ย้ายไปยังอุปกรณ์อื่น"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"วิธีง่ายๆ ในการลงชื่อเข้าใช้อย่างปลอดภัย"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ใช้ลายนิ้วมือ ใบหน้า หรือล็อกหน้าจอในการลงชื่อเข้าใช้ด้วยพาสคีย์ที่ไม่ซ้ำกันเพื่อไม่ให้ลืมหรือถูกขโมยได้ ดูข้อมูลเพิ่มเติม"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"เลือกตำแหน่งที่จะ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"เลือกตำแหน่งที่จะ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"สร้างพาสคีย์"</string>
<string name="save_your_password" msgid="6597736507991704307">"บันทึกรหัสผ่าน"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"บันทึกข้อมูลการลงชื่อเข้าใช้"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"ตั้งค่าเครื่องมือจัดการรหัสผ่านเริ่มต้นเพื่อบันทึกรหัสผ่านและพาสคีย์ของคุณ และลงชื่อเข้าใช้ได้เร็วขึ้นในครั้งถัดไป"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"สร้างพาสคีย์ใน <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ใช่ไหม"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"บันทึกรหัสผ่านลงใน <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ใช่ไหม"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"บันทึกข้อมูลการลงชื่อเข้าใช้ลงใน <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ใช่ไหม"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"พาสคีย์"</string>
<string name="password" msgid="6738570945182936667">"รหัสผ่าน"</string>
<string name="sign_ins" msgid="4710739369149469208">"การลงชื่อเข้าใช้"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"สร้างพาสคีย์ใน"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"บันทึกรหัสผ่านลงใน"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"บันทึกการลงชื่อเข้าใช้ไปยัง"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"สร้างพาสคีย์ในอุปกรณ์อื่นไหม"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"ใช้ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> สำหรับการลงชื่อเข้าใช้ทั้งหมดใช่ไหม"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"เครื่องมือจัดการรหัสผ่านนี้จะจัดเก็บรหัสผ่านและพาสคีย์ไว้เพื่อช่วยให้คุณลงชื่อเข้าใช้ได้โดยง่าย"</string>
<string name="set_as_default" msgid="4415328591568654603">"ตั้งเป็นค่าเริ่มต้น"</string>
<string name="use_once" msgid="9027366575315399714">"ใช้ครั้งเดียว"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"รหัสผ่าน <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> รายการ พาสคีย์ <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> รายการ"</string>
diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
index 01fd2f02063d..d5501908aa13 100644
--- a/packages/CredentialManager/res/values-tl/strings.xml
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"I-save sa ibang lugar"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Gumamit ng ibang device"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"I-save sa ibang device"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Simpleng paraan para mag-sign in lang ligtas"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gamitin ang iyong fingerprint, mukha, o lock ng screen para mag-sign in gamit ang natatanging passkey na hindi makakalimutan o mananakaw. Matuto pa"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Piliin kung saan <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Piliin kung saan <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"gawin ang iyong mga passkey"</string>
<string name="save_your_password" msgid="6597736507991704307">"i-save ang iyong password"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"i-save ang iyong impormasyon sa pag-sign in"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Magtakda ng default na password manager para i-save ang iyong mga password at passkey at mag-sign in nang mas mabilis sa susunod."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Gumawa ng passkey sa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"I-save ang iyong password sa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"I-save ang iyong impormasyon sa pag-sign in sa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="sign_ins" msgid="4710739369149469208">"mga sign-in"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Gumawa ng passkey sa"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"I-save ang password sa"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"I-save ang sign-in sa"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Gumawa ng passkey sa ibang device?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gamitin ang <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para sa lahat ng iyong pag-sign in?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Iso-store ng password manager na ito ang iyong mga password at passkey para madali kang makapag-sign in."</string>
<string name="set_as_default" msgid="4415328591568654603">"Itakda bilang default"</string>
<string name="use_once" msgid="9027366575315399714">"Gamitin nang isang beses"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> (na) password, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> (na) passkey"</string>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
index 30ed43e6ed19..09c659027bb3 100644
--- a/packages/CredentialManager/res/values-tr/strings.xml
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Kimlik Bilgisi Yöneticisi"</string>
<string name="string_cancel" msgid="6369133483981306063">"İptal"</string>
<string name="string_continue" msgid="1346732695941131882">"Devam"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Başka bir yerde oluşturun"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Başka bir yere kaydedin"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Başka bir cihaz kullan"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Başka bir cihaza kaydet"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Güvenli bir şekilde oturum açmanın basit yolu"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Parmak iziniz, yüzünüz ya da ekran kilidinizi kullanarak unutması veya çalınması mümkün olmayan benzersiz bir şifre anahtarıyla oturum açın. Daha fazla bilgi"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> yerini seçin"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> yerini seçin"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"şifre anahtarlarınızı oluşturun"</string>
<string name="save_your_password" msgid="6597736507991704307">"şifrenizi kaydedin"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"oturum açma bilgilerinizi kaydedin"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Şifrelerinizi ve şifre anahtarlarınızı kaydedip bir dahaki sefere daha hızlı oturum açmak için varsayılan bir şifre yöneticisi belirleyin."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> içinde şifre anahtarı oluşturulsun mu?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Şifreniz <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> içine kaydedilsin mi?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Oturum açma bilgileriniz <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> içine kaydedilsin mi?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"şifre anahtarı"</string>
<string name="password" msgid="6738570945182936667">"şifre"</string>
<string name="sign_ins" msgid="4710739369149469208">"oturum aç"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Şifre anahtarının oluşturulacağı yer:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Şifreyi şuraya kaydet:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Oturum açma bilgilerinin kaydedileceği yer:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Başka bir cihazda şifre anahtarı oluşturulsun mu?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Tüm oturum açma işlemlerinizde <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kullanılsın mı?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Bu şifre yöneticisi, şifrelerinizi ve şifre anahtarlarınızı saklayarak kolayca oturum açmanıza yardımcı olur."</string>
<string name="set_as_default" msgid="4415328591568654603">"Varsayılan olarak ayarla"</string>
<string name="use_once" msgid="9027366575315399714">"Bir kez kullanın"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> şifre, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> şifre anahtarı"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> şifre"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> şifre anahtarı"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Şifre anahtarı"</string>
<string name="another_device" msgid="5147276802037801217">"Başka bir cihaz"</string>
<string name="other_password_manager" msgid="565790221427004141">"Diğer şifre yöneticileri"</string>
<string name="close_sheet" msgid="1393792015338908262">"Sayfayı kapat"</string>
diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml
index 69d4612eb594..9a12e331dff2 100644
--- a/packages/CredentialManager/res/values-uk/strings.xml
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Диспетчер облікових даних"</string>
<string name="string_cancel" msgid="6369133483981306063">"Скасувати"</string>
<string name="string_continue" msgid="1346732695941131882">"Продовжити"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Створити в іншому місці"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Зберегти в іншому місці"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Скористатись іншим пристроєм"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Зберегти на іншому пристрої"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Зручний спосіб для безпечного входу"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Користуйтеся відбитком пальця, фейсконтролем або іншим способом розблокування екрана, щоб входити в обліковий запис за допомогою унікального ключа доступу, який неможливо забути чи викрасти. Докладніше"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Виберіть, де <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Виберіть, де <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"створювати ключі доступу"</string>
<string name="save_your_password" msgid="6597736507991704307">"зберегти пароль"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"зберегти дані для входу"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Налаштуйте менеджер паролів за умовчанням, щоб зберігати свої паролі та ключі доступу й надалі входити в облікові записи швидше."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Створити ключ доступу в сервісі <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Зберегти ваш пароль у сервісі <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Зберегти ваші дані для входу в сервіс <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
<string name="password" msgid="6738570945182936667">"пароль"</string>
<string name="sign_ins" msgid="4710739369149469208">"дані для входу"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Створити ключ доступу в"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Зберегти пароль в обліковому записі"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Зберегти дані для входу в обліковий запис"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Створити ключ доступу на іншому пристрої?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Використовувати сервіс <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> в усіх випадках входу?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Цей менеджер паролів зберігатиме ваші паролі та ключі доступу, щоб ви могли легко входити в облікові записи."</string>
<string name="set_as_default" msgid="4415328591568654603">"Вибрати за умовчанням"</string>
<string name="use_once" msgid="9027366575315399714">"Скористатися раз"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Кількість паролів: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>; кількість ключів доступу: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Кількість паролів: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Кількість ключів доступу: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Ключ доступу"</string>
<string name="another_device" msgid="5147276802037801217">"Інший пристрій"</string>
<string name="other_password_manager" msgid="565790221427004141">"Інші менеджери паролів"</string>
<string name="close_sheet" msgid="1393792015338908262">"Закрити аркуш"</string>
diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml
index 2d6607934bc0..50fbb8d53fcb 100644
--- a/packages/CredentialManager/res/values-ur/strings.xml
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"دوسرے مقام میں محفوظ کریں"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"کوئی دوسرا آلہ استعمال کریں"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"دوسرے آلے میں محفوظ کریں"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"محفوظ طریقے سے سائن ان کرنے کا آسان طریقہ"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"اپنے فنگر پرنٹ، چہرے یا اسکرین لاک کا استعمال کریں تاکہ ایک ایسی منفرد پاس کی سے سائن ان کیا جا سکے جسے بھولا یا چوری نہیں کیا جا سکتا۔ مزید جانیں"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> کی جگہ منتخب کریں"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> کی جگہ منتخب کریں"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"اپنی پاس کیز تخلیق کریں"</string>
<string name="save_your_password" msgid="6597736507991704307">"اپنا پاس ورڈ محفوظ کریں"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"اپنے سائن ان کی معلومات محفوظ کریں"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"اپنے پاس ورڈز اور پاس کیز کو محفوظ کرنے اور اگلی بار تیزی سے سائن ان کرنے کے لیے ایک ڈیفالٹ پاس ورڈ مینیجر سیٹ کریں۔"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> میں پاس کی تخلیق کریں؟"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"اپنا پاس ورڈ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> میں محفوظ کریں؟"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"اپنے سائن ان کی معلومات کو <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> میں محفوظ کریں؟"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"پاس کی"</string>
<string name="password" msgid="6738570945182936667">"پاس ورڈ"</string>
<string name="sign_ins" msgid="4710739369149469208">"سائن انز"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"اس میں پاس کی تخلیق کریں"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"میں پاس ورڈ محفوظ کریں"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"میں سائن ان محفوظ کریں"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"کسی اور آلے میں پاس کی تخلیق کریں؟"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"اپنے سبھی سائن انز کے لیے <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> کا استعمال کریں؟"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"یہ پاس ورڈ مینیجر آپ کے پاس ورڈز اور پاس کیز کو آسانی سے سائن ان کرنے میں آپ کی مدد کرنے کے لیے اسٹور کرے گا۔"</string>
<string name="set_as_default" msgid="4415328591568654603">"بطور ڈیفالٹ سیٹ کریں"</string>
<string name="use_once" msgid="9027366575315399714">"ایک بار استعمال کریں"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> پاس ورڈز، <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> پاس کیز"</string>
diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml
index 4ac35b2e6f7d..b46979aef749 100644
--- a/packages/CredentialManager/res/values-uz/strings.xml
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Hisob maʼlumotlari menejeri"</string>
<string name="string_cancel" msgid="6369133483981306063">"Bekor qilish"</string>
<string name="string_continue" msgid="1346732695941131882">"Davom etish"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Boshqa joyda yaratish"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Boshqa joyga saqlash"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Boshqa qurilmadan foydalaning"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Boshqa qurilmaga saqlash"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Xavfsiz kirishning oddiy usuli"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Esda qoladigan maxsus kalit bilan kirishda barmoq izi, yuz axboroti yoki ekran qulfidan foydalaning. Batafsil"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> joyini tanlang"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> joyini tanlang"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"kodlar yaratish"</string>
<string name="save_your_password" msgid="6597736507991704307">"Parolni saqlash"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"kirish axborotini saqlang"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Parol va kodlarni saqlash va keyingi safar tezroq kirish uchun standart parollar menejerini sozlang."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Kalit <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xizmatida yaratilsinmi?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Parol <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xizmatida saqlansinmi?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Hisob maʼlumotlari <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xizmatida saqlansinmi?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"kalit"</string>
<string name="password" msgid="6738570945182936667">"parol"</string>
<string name="sign_ins" msgid="4710739369149469208">"kirishlar"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Kod yaratish vositasi"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Parolni bu hisobga saqlash"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Kirish axborotini saqlash"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Boshqa qurilmada kod yaratilsinmi?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Hamma kirishlarda <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ishlatilsinmi?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Bu parollar menejerida hisobga oson kirishga yordam beruvchi parol va kalitlar saqlanadi."</string>
<string name="set_as_default" msgid="4415328591568654603">"Birlamchi deb belgilash"</string>
<string name="use_once" msgid="9027366575315399714">"Bir marta ishlatish"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ta parol, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ta kalit"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ta parol"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ta kalit"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Kod"</string>
<string name="another_device" msgid="5147276802037801217">"Boshqa qurilma"</string>
<string name="other_password_manager" msgid="565790221427004141">"Boshqa parol menejerlari"</string>
<string name="close_sheet" msgid="1393792015338908262">"Varaqni yopish"</string>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
index fd5b986c574b..6c3022ec3b60 100644
--- a/packages/CredentialManager/res/values-vi/strings.xml
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Trình quản lý thông tin xác thực"</string>
<string name="string_cancel" msgid="6369133483981306063">"Huỷ"</string>
<string name="string_continue" msgid="1346732695941131882">"Tiếp tục"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Tạo ở vị trí khác"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Lưu vào vị trí khác"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Dùng thiết bị khác"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Lưu vào thiết bị khác"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Cách đơn giản để đăng nhập an toàn"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Dùng vân tay, khuôn mặt hoặc phương thức khoá màn hình để đăng nhập bằng một mã xác thực duy nhất mà bạn không lo sẽ quên hay bị đánh cắp. Tìm hiểu thêm"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"Chọn vị trí <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"Chọn vị trí <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"tạo mã xác thực"</string>
<string name="save_your_password" msgid="6597736507991704307">"lưu mật khẩu của bạn"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"lưu thông tin đăng nhập của bạn"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"Đặt một trình quản lý mật khẩu mặc định để lưu mật khẩu và mã xác thực của bạn, nhờ đó, bạn sẽ đăng nhập nhanh hơn vào lần sau."</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Tạo một mã xác thực trong <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"Lưu mật khẩu của bạn vào <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Lưu thông tin đăng nhập của bạn vào <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"mã xác thực"</string>
<string name="password" msgid="6738570945182936667">"mật khẩu"</string>
<string name="sign_ins" msgid="4710739369149469208">"thông tin đăng nhập"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"Tạo mã xác thực trong"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"Lưu mật khẩu vào"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"Lưu thông tin đăng nhập vào"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Tạo mã xác thực trong một thiết bị khác?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Dùng <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> cho mọi thông tin đăng nhập của bạn?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"Trình quản lý mật khẩu này sẽ lưu trữ mật khẩu và mã xác thực của bạn để bạn dễ dàng đăng nhập."</string>
<string name="set_as_default" msgid="4415328591568654603">"Đặt làm mặc định"</string>
<string name="use_once" msgid="9027366575315399714">"Dùng một lần"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mật khẩu, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> mã xác thực"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mật khẩu"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> mã xác thực"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Mã xác thực"</string>
<string name="another_device" msgid="5147276802037801217">"Thiết bị khác"</string>
<string name="other_password_manager" msgid="565790221427004141">"Trình quản lý mật khẩu khác"</string>
<string name="close_sheet" msgid="1393792015338908262">"Đóng trang tính"</string>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index a14dd2f6fe20..9e6c514bd83e 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
<string name="string_cancel" msgid="6369133483981306063">"取消"</string>
<string name="string_continue" msgid="1346732695941131882">"继续"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"在另一位置创建"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"保存到另一位置"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"使用另一台设备"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"保存到其他设备"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"简单又安全的登录方式"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"借助指纹、人脸识别或屏幕锁定功能,使用不会被忘记或被盗且具有唯一性的通行密钥登录。了解详情"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"选择<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"选择<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"创建通行密钥"</string>
<string name="save_your_password" msgid="6597736507991704307">"保存您的密码"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"保存您的登录信息"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"设置默认密码管理工具,以便保存您的密码和通行密钥,从而提高下次的登录速度。"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"在“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”中创建通行密钥?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"将您的密码保存至“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"将您的登录信息保存至“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”?"</string>
@@ -25,24 +28,18 @@
<string name="passkey" msgid="632353688396759522">"通行密钥"</string>
<string name="password" msgid="6738570945182936667">"密码"</string>
<string name="sign_ins" msgid="4710739369149469208">"登录"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"在以下位置创建通行密钥"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"将密码保存到"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"将登录信息保存到"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"在其他设备上创建通行密钥?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"将“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”用于您的所有登录信息?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"此密码管理工具将会存储您的密码和通行密钥,以帮助您轻松登录。"</string>
<string name="set_as_default" msgid="4415328591568654603">"设为默认项"</string>
<string name="use_once" msgid="9027366575315399714">"使用一次"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 个密码,<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 个通行密钥"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 个密码"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> 个通行密钥"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"通行密钥"</string>
<string name="another_device" msgid="5147276802037801217">"另一台设备"</string>
<string name="other_password_manager" msgid="565790221427004141">"其他密码管理工具"</string>
<string name="close_sheet" msgid="1393792015338908262">"关闭工作表"</string>
diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml
index 71dfa1affb72..cc596d702da9 100644
--- a/packages/CredentialManager/res/values-zh-rHK/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"儲存至其他位置"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"改用其他裝置"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"儲存至其他裝置"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"安全又簡便的登入方式"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"使用指紋、面孔或螢幕鎖定配合密鑰登入。密鑰獨一無二,您不用擔心忘記密鑰或密鑰被盜。瞭解詳情"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"建立密鑰"</string>
<string name="save_your_password" msgid="6597736507991704307">"儲存密碼"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"儲存登入資料"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"設定預設的密碼管理工具以儲存密碼和密碼密鑰,下次就能更快速登入。"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"要在「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」建立密鑰嗎?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"要將密碼儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"要將登入資料儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
@@ -24,23 +28,18 @@
<string name="passkey" msgid="632353688396759522">"密鑰"</string>
<string name="password" msgid="6738570945182936667">"密碼"</string>
<string name="sign_ins" msgid="4710739369149469208">"登入資料"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"在此裝置建立密鑰:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"將密碼儲存至以下位置:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"將登入資料儲存至以下位置:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"要在另一部裝置上建立密鑰嗎?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"要將「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」用於所有的登入資料嗎?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"此密碼管理工具將儲存您的密碼和密鑰,協助您輕鬆登入。"</string>
<string name="set_as_default" msgid="4415328591568654603">"設定為預設"</string>
<string name="use_once" msgid="9027366575315399714">"單次使用"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼,<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 個密鑰"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> 個密鑰"</string>
- <string name="passkey_before_subtitle" msgid="2448119456208647444">"密碼金鑰"</string>
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"密鑰"</string>
<string name="another_device" msgid="5147276802037801217">"其他裝置"</string>
<string name="other_password_manager" msgid="565790221427004141">"其他密碼管理工具"</string>
<string name="close_sheet" msgid="1393792015338908262">"閂工作表"</string>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
index 0d636c24cca2..1fa1bd677a8d 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -8,15 +8,19 @@
<string name="string_save_to_another_place" msgid="7590325934591079193">"儲存至其他位置"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"改用其他裝置"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"儲存至其他裝置"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"安全又簡單的登入方式"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"登入帳戶時,你可以使用指紋、人臉或螢幕鎖定功能搭配不重複的密碼金鑰,不必擔心忘記密碼金鑰或遭人竊取。瞭解詳情"</string>
- <string name="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
- <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
<skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
+ <string name="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
+ <string name="create_your_passkeys" msgid="8901224153607590596">"建立金鑰密碼"</string>
<string name="save_your_password" msgid="6597736507991704307">"儲存密碼"</string>
<string name="save_your_sign_in_info" msgid="7213978049817076882">"儲存登入資訊"</string>
- <!-- no translation found for choose_provider_body (8045759834416308059) -->
- <skip />
+ <string name="choose_provider_body" msgid="8045759834416308059">"你可以設定預設的密碼管理工具以儲存密碼和密碼金鑰,下次就能更快速登入。"</string>
<string name="choose_create_option_passkey_title" msgid="4146408187146573131">"要在「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」建立密碼金鑰嗎?"</string>
<string name="choose_create_option_password_title" msgid="8812546498357380545">"要將密碼儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
<string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"要將登入資訊儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
@@ -24,17 +28,12 @@
<string name="passkey" msgid="632353688396759522">"密碼金鑰"</string>
<string name="password" msgid="6738570945182936667">"密碼"</string>
<string name="sign_ins" msgid="4710739369149469208">"登入資訊"</string>
- <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
- <skip />
- <!-- no translation found for save_password_to_title (3450480045270186421) -->
- <skip />
- <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
- <skip />
- <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
- <skip />
+ <string name="create_passkey_in_title" msgid="2714306562710897785">"在以下位置建立密碼金鑰:"</string>
+ <string name="save_password_to_title" msgid="3450480045270186421">"將密碼儲存到以下位置:"</string>
+ <string name="save_sign_in_to_title" msgid="8328143607671760232">"將登入資訊儲存到以下位置:"</string>
+ <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"要在另一部裝置上建立密碼金鑰嗎?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"要將「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」用於所有的登入資訊嗎?"</string>
- <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
- <skip />
+ <string name="use_provider_for_all_description" msgid="6560593199974037820">"這個密碼管理工具會儲存你的密碼和密碼金鑰,協助你輕鬆登入。"</string>
<string name="set_as_default" msgid="4415328591568654603">"設為預設"</string>
<string name="use_once" msgid="9027366575315399714">"單次使用"</string>
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼,<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 個密碼金鑰"</string>
diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
index a35c6d2af737..772104dfbb0c 100644
--- a/packages/CredentialManager/res/values-zu/strings.xml
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -1,16 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (4539824758261855508) -->
- <skip />
+ <string name="app_name" msgid="4539824758261855508">"Umphathi Wezimfanelo"</string>
<string name="string_cancel" msgid="6369133483981306063">"Khansela"</string>
<string name="string_continue" msgid="1346732695941131882">"Qhubeka"</string>
<string name="string_create_in_another_place" msgid="1033635365843437603">"Sungula kwenye indawo"</string>
<string name="string_save_to_another_place" msgid="7590325934591079193">"Londoloza kwenye indawo"</string>
<string name="string_use_another_device" msgid="8754514926121520445">"Sebenzisa enye idivayisi"</string>
<string name="string_save_to_another_device" msgid="1959562542075194458">"Londoloza kwenye idivayisi"</string>
- <string name="passkey_creation_intro_title" msgid="402553911484409884">"Indlela elula yokungena ngemvume ngokuphephile"</string>
- <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Sebenzisa isigxivizo somunwe, ubuso noma ukukhiya isikrini ukuze ungene ngemvume ngokhiye wokudlula oyingqayizivele ongenakulibaleka noma owebiwe. Funda kabanzi"</string>
+ <!-- no translation found for passkey_creation_intro_title (4251037543787718844) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_password (312712407571126228) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_fingerprint (691816235541508203) -->
+ <skip />
+ <!-- no translation found for passkey_creation_intro_body_device (477121861162321129) -->
+ <skip />
<string name="choose_provider_title" msgid="7245243990139698508">"Khetha lapho onga-<xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<!-- no translation found for create_your_passkeys (8901224153607590596) -->
<skip />
@@ -41,8 +46,7 @@
<string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Amaphasiwedi angu-<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, okhiye bokudlula abangu-<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Amaphasiwedi angu-<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Okhiye bokudlula abangu-<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
- <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
- <skip />
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Ukhiye wokudlula"</string>
<string name="another_device" msgid="5147276802037801217">"Enye idivayisi"</string>
<string name="other_password_manager" msgid="565790221427004141">"Abanye abaphathi bephasiwedi"</string>
<string name="close_sheet" msgid="1393792015338908262">"Vala ishidi"</string>
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 870d9832ca0b..a3ebf1efbb51 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -80,6 +80,8 @@
<string name="close_sheet">"Close sheet"</string>
<!-- Spoken content description of the back arrow button. -->
<string name="accessibility_back_arrow_button">"Go back to the previous page"</string>
+ <!-- Spoken content description of the close button. -->
+ <string name="accessibility_close_button">"Close the Credential Manager action suggestion appearing at the bottom of the screen"</string>
<!-- Strings for the get flow. -->
<!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved passkey to sign in to the app. [CHAR LIMIT=200] -->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index f801ba61e073..4faf00c43d34 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -44,7 +44,6 @@ import com.android.credentialmanager.createflow.CreateCredentialUiState
import com.android.credentialmanager.createflow.EnabledProviderInfo
import com.android.credentialmanager.createflow.RemoteInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
-import com.android.credentialmanager.getflow.GetScreenState
import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest.Companion.toBundle
import com.android.credentialmanager.jetpack.developer.CreatePublicKeyCredentialRequest
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
@@ -64,7 +63,7 @@ class CredentialManagerRepo(
requestInfo = intent.extras?.getParcelable(
RequestInfo.EXTRA_REQUEST_INFO,
RequestInfo::class.java
- ) ?: testCreatePasskeyRequestInfo()
+ ) ?: testGetRequestInfo()
providerEnabledList = when (requestInfo.type) {
RequestInfo.TYPE_CREATE ->
@@ -124,11 +123,9 @@ class CredentialManagerRepo(
val providerEnabledList = GetFlowUtils.toProviderList(
// TODO: handle runtime cast error
providerEnabledList as List<GetCredentialProviderData>, context)
- // TODO: covert from real requestInfo
- val requestDisplayInfo = com.android.credentialmanager.getflow.RequestDisplayInfo("the app")
+ val requestDisplayInfo = GetFlowUtils.toRequestDisplayInfo(requestInfo)
return GetCredentialUiState(
providerEnabledList,
- GetScreenState.PRIMARY_SELECTION,
requestDisplayInfo,
)
}
@@ -248,12 +245,10 @@ class CredentialManagerRepo(
listOf(
newActionEntry(
"key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
- Icon.createWithResource(context, R.drawable.ic_manage_accounts),
"Open Google Password Manager", "elisa.beckett@gmail.com"
),
newActionEntry(
"key3", "subkey-2", TYPE_PASSWORD_CREDENTIAL,
- Icon.createWithResource(context, R.drawable.ic_manage_accounts),
"Open Google Password Manager", "beckett-family@gmail.com"
),
)
@@ -278,7 +273,6 @@ class CredentialManagerRepo(
listOf(
newActionEntry(
"key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
- Icon.createWithResource(context, R.drawable.ic_face),
"Open Enpass"
),
)
@@ -290,7 +284,6 @@ class CredentialManagerRepo(
key: String,
subkey: String,
credentialType: String,
- icon: Icon,
text: String,
subtext: String? = null,
): Entry {
@@ -298,7 +291,7 @@ class CredentialManagerRepo(
Entry.CREDENTIAL_MANAGER_ENTRY_URI, SliceSpec(credentialType, 1)
).addText(
text, null, listOf(Entry.HINT_ACTION_TITLE)
- ).addIcon(icon, null, listOf(Entry.HINT_ACTION_ICON))
+ )
if (subtext != null) {
slice.addText(subtext, null, listOf(Entry.HINT_ACTION_SUBTEXT))
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 0d7e81984ead..56fbf6632dc5 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -67,7 +67,8 @@ class GetFlowUtils {
.getPackageInfo(packageName!!,
PackageManager.PackageInfoFlags.of(0))
val providerDisplayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString()
- // TODO: decide what to do when failed to load a provider icon
+ // TODO: get the provider icon from the service
+ // and decide what to do when failed to load a provider icon
val providerIcon = pkgInfo.applicationInfo.loadIcon(packageManager)!!
ProviderInfo(
id = it.providerFlattenedComponentName,
@@ -83,11 +84,19 @@ class GetFlowUtils {
it.authenticationEntry),
remoteEntry = getRemoteEntry(it.providerFlattenedComponentName, it.remoteEntry),
actionEntryList = getActionEntryList(
- it.providerFlattenedComponentName, it.actionChips, context),
+ it.providerFlattenedComponentName, it.actionChips, providerIcon),
)
}
}
+ fun toRequestDisplayInfo(
+ requestInfo: RequestInfo,
+ ): com.android.credentialmanager.getflow.RequestDisplayInfo {
+ return com.android.credentialmanager.getflow.RequestDisplayInfo(
+ appDomainName = requestInfo.appPackageName
+ )
+ }
+
/* From service data structure to UI credential entry list representation. */
private fun getCredentialOptionInfoList(
@@ -111,7 +120,7 @@ class GetFlowUtils {
displayName = credentialEntryUi.userDisplayName?.toString(),
// TODO: proper fallback
icon = credentialEntryUi.entryIcon?.loadDrawable(context)
- ?: context.getDrawable(R.drawable.ic_passkey)!!,
+ ?: context.getDrawable(R.drawable.ic_other_sign_in)!!,
lastUsedTimeMillis = credentialEntryUi.lastUsedTimeMillis,
)
}
@@ -156,7 +165,7 @@ class GetFlowUtils {
private fun getActionEntryList(
providerId: String,
actionEntries: List<Entry>,
- context: Context,
+ providerIcon: Drawable,
): List<ActionEntryInfo> {
return actionEntries.map {
val actionEntryUi = ActionUi.fromSlice(it.slice)
@@ -169,7 +178,7 @@ class GetFlowUtils {
fillInIntent = it.frameworkExtrasIntent,
title = actionEntryUi.text.toString(),
// TODO: gracefully fail
- icon = actionEntryUi.icon.loadDrawable(context)!!,
+ icon = providerIcon,
subTitle = actionEntryUi.subtext?.toString(),
)
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index b417b385ada7..c26fac8895ab 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -313,7 +313,7 @@ fun ProviderSelectionCard(
}
}
}
- if (disabledProviderList != null) {
+ if (disabledProviderList != null && disabledProviderList.isNotEmpty()) {
item {
MoreOptionsDisabledProvidersRow(
disabledProviders = disabledProviderList,
@@ -431,14 +431,12 @@ fun MoreOptionsSelectionCard(
}
}
}
- if (disabledProviderList != null) {
- item {
- MoreOptionsDisabledProvidersRow(
- disabledProviders = disabledProviderList,
- onDisabledPasswordManagerSelected =
- onDisabledPasswordManagerSelected,
- )
- }
+ item {
+ MoreOptionsDisabledProvidersRow(
+ disabledProviders = disabledProviderList,
+ onDisabledPasswordManagerSelected =
+ onDisabledPasswordManagerSelected,
+ )
}
// TODO: handle the error situation that if multiple remoteInfos exists
enabledProviderList.forEach {
@@ -748,7 +746,7 @@ fun PrimaryCreateOptionRow(
},
contentDescription = null,
tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
- modifier = Modifier.padding(horizontal = 18.dp).size(32.dp)
+ modifier = Modifier.padding(start = 10.dp).size(32.dp)
)
},
label = {
@@ -759,7 +757,7 @@ fun PrimaryCreateOptionRow(
TextOnSurfaceVariant(
text = requestDisplayInfo.title,
style = MaterialTheme.typography.titleLarge,
- modifier = Modifier.padding(top = 16.dp),
+ modifier = Modifier.padding(top = 16.dp, start = 5.dp),
)
TextSecondary(
text = if (requestDisplayInfo.subtitle != null) {
@@ -770,27 +768,27 @@ fun PrimaryCreateOptionRow(
stringResource(R.string.passkey_before_subtitle)
},
style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp),
+ modifier = Modifier.padding(bottom = 16.dp, start = 5.dp),
)
}
TYPE_PASSWORD_CREDENTIAL -> {
TextOnSurfaceVariant(
text = requestDisplayInfo.title,
style = MaterialTheme.typography.titleLarge,
- modifier = Modifier.padding(top = 16.dp),
+ modifier = Modifier.padding(top = 16.dp, start = 5.dp),
)
TextSecondary(
// This subtitle would never be null for create password
text = requestDisplayInfo.subtitle ?: "",
style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp),
+ modifier = Modifier.padding(bottom = 16.dp, start = 5.dp),
)
}
else -> {
TextOnSurfaceVariant(
text = requestDisplayInfo.title,
style = MaterialTheme.typography.titleLarge,
- modifier = Modifier.padding(top = 16.dp, bottom = 16.dp),
+ modifier = Modifier.padding(top = 16.dp, bottom = 16.dp, start = 5.dp),
)
}
}
@@ -810,7 +808,7 @@ fun MoreOptionsInfoRow(
onClick = onOptionSelected,
icon = {
Image(
- modifier = Modifier.padding(horizontal = 16.dp).size(32.dp),
+ modifier = Modifier.padding(start = 10.dp).size(32.dp),
bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
contentDescription = null
)
@@ -820,12 +818,18 @@ fun MoreOptionsInfoRow(
TextOnSurfaceVariant(
text = providerInfo.displayName,
style = MaterialTheme.typography.titleLarge,
- modifier = Modifier.padding(top = 16.dp),
+ modifier = Modifier.padding(top = 16.dp, start = 5.dp),
)
if (createOptionInfo.userProviderDisplayName != null) {
TextSecondary(
text = createOptionInfo.userProviderDisplayName,
style = MaterialTheme.typography.bodyMedium,
+ // TODO: update the logic here for the case there is only total count
+ modifier = if (
+ createOptionInfo.passwordCount != null ||
+ createOptionInfo.passkeyCount != null
+ ) Modifier.padding(start = 5.dp) else Modifier
+ .padding(bottom = 16.dp, start = 5.dp),
)
}
if (createOptionInfo.passwordCount != null &&
@@ -839,7 +843,7 @@ fun MoreOptionsInfoRow(
createOptionInfo.passkeyCount
),
style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp),
+ modifier = Modifier.padding(bottom = 16.dp, start = 5.dp),
)
} else if (createOptionInfo.passwordCount != null) {
TextSecondary(
@@ -849,7 +853,7 @@ fun MoreOptionsInfoRow(
createOptionInfo.passwordCount
),
style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp),
+ modifier = Modifier.padding(bottom = 16.dp, start = 5.dp),
)
} else if (createOptionInfo.passkeyCount != null) {
TextSecondary(
@@ -859,7 +863,7 @@ fun MoreOptionsInfoRow(
createOptionInfo.passkeyCount
),
style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp),
+ modifier = Modifier.padding(bottom = 16.dp, start = 5.dp),
)
} else if (createOptionInfo.totalCredentialCount != null) {
// TODO: Handle the case when there is total count
@@ -873,34 +877,36 @@ fun MoreOptionsInfoRow(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MoreOptionsDisabledProvidersRow(
- disabledProviders: List<ProviderInfo>,
+ disabledProviders: List<ProviderInfo>?,
onDisabledPasswordManagerSelected: () -> Unit,
) {
- Entry(
- onClick = onDisabledPasswordManagerSelected,
- icon = {
- Icon(
- Icons.Filled.Add,
- contentDescription = null,
- modifier = Modifier.padding(start = 16.dp)
- )
- },
- label = {
- Column() {
- TextOnSurfaceVariant(
- text = stringResource(R.string.other_password_manager),
- style = MaterialTheme.typography.titleLarge,
- modifier = Modifier.padding(top = 16.dp, start = 16.dp),
- )
- // TODO: Update the subtitle once design is confirmed
- TextSecondary(
- text = disabledProviders.joinToString(separator = ", ") { it.displayName },
- style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp, start = 16.dp),
+ if (disabledProviders != null && disabledProviders.isNotEmpty()) {
+ Entry(
+ onClick = onDisabledPasswordManagerSelected,
+ icon = {
+ Icon(
+ Icons.Filled.Add,
+ contentDescription = null,
+ modifier = Modifier.padding(start = 16.dp)
)
+ },
+ label = {
+ Column() {
+ TextOnSurfaceVariant(
+ text = stringResource(R.string.other_password_manager),
+ style = MaterialTheme.typography.titleLarge,
+ modifier = Modifier.padding(top = 16.dp, start = 5.dp),
+ )
+ // TODO: Update the subtitle once design is confirmed
+ TextSecondary(
+ text = disabledProviders.joinToString(separator = ", ") { it.displayName },
+ style = MaterialTheme.typography.bodyMedium,
+ modifier = Modifier.padding(bottom = 16.dp, start = 5.dp),
+ )
+ }
}
- }
- )
+ )
+ }
}
@OptIn(ExperimentalMaterial3Api::class)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index d6d71220e943..619f5a37d45b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -16,6 +16,7 @@
package com.android.credentialmanager.getflow
+import android.credentials.Credential
import android.text.TextUtils
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
@@ -32,15 +33,20 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material.icons.outlined.Lock
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Snackbar
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
@@ -65,6 +71,7 @@ import com.android.credentialmanager.common.ui.ContainerCard
import com.android.credentialmanager.common.ui.TransparentBackgroundEntry
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential
import com.android.credentialmanager.ui.theme.EntryShape
+import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
@Composable
fun GetCredentialScreen(
@@ -75,39 +82,50 @@ fun GetCredentialScreen(
initialValue = ModalBottomSheetValue.Expanded,
skipHalfExpanded = true
)
- ModalBottomSheetLayout(
- sheetBackgroundColor = MaterialTheme.colorScheme.surface,
- modifier = Modifier.background(Color.Transparent),
- sheetState = state,
- sheetContent = {
- val uiState = viewModel.uiState
- if (!uiState.hidden) {
- when (uiState.currentScreenState) {
- GetScreenState.PRIMARY_SELECTION -> PrimarySelectionCard(
- requestDisplayInfo = uiState.requestDisplayInfo,
- providerDisplayInfo = uiState.providerDisplayInfo,
- onEntrySelected = viewModel::onEntrySelected,
- onCancel = viewModel::onCancel,
- onMoreOptionSelected = viewModel::onMoreOptionSelected,
- )
- GetScreenState.ALL_SIGN_IN_OPTIONS -> AllSignInOptionCard(
- providerInfoList = uiState.providerInfoList,
- providerDisplayInfo = uiState.providerDisplayInfo,
- onEntrySelected = viewModel::onEntrySelected,
- onBackButtonClicked = viewModel::onBackToPrimarySelectionScreen,
- )
+ val uiState = viewModel.uiState
+ if (uiState.currentScreenState != GetScreenState.REMOTE_ONLY) {
+ ModalBottomSheetLayout(
+ sheetBackgroundColor = MaterialTheme.colorScheme.surface,
+ modifier = Modifier.background(Color.Transparent),
+ sheetState = state,
+ sheetContent = {
+ // TODO: hide UI at top level
+ if (!uiState.hidden) {
+ if (uiState.currentScreenState == GetScreenState.PRIMARY_SELECTION) {
+ PrimarySelectionCard(
+ requestDisplayInfo = uiState.requestDisplayInfo,
+ providerDisplayInfo = uiState.providerDisplayInfo,
+ onEntrySelected = viewModel::onEntrySelected,
+ onCancel = viewModel::onCancel,
+ onMoreOptionSelected = viewModel::onMoreOptionSelected,
+ )
+ } else {
+ AllSignInOptionCard(
+ providerInfoList = uiState.providerInfoList,
+ providerDisplayInfo = uiState.providerDisplayInfo,
+ onEntrySelected = viewModel::onEntrySelected,
+ onBackButtonClicked = viewModel::onBackToPrimarySelectionScreen,
+ onCancel = viewModel::onCancel,
+ isNoAccount = uiState.isNoAccount,
+ )
+ }
+ } else if (uiState.selectedEntry != null && !uiState.providerActivityPending) {
+ viewModel.launchProviderUi(providerActivityLauncher)
}
- } else if (uiState.selectedEntry != null && !uiState.providerActivityPending) {
- viewModel.launchProviderUi(providerActivityLauncher)
+ },
+ scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
+ sheetShape = EntryShape.TopRoundedCorner,
+ ) {}
+ LaunchedEffect(state.currentValue) {
+ if (state.currentValue == ModalBottomSheetValue.Hidden) {
+ viewModel.onCancel()
}
- },
- scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
- sheetShape = EntryShape.TopRoundedCorner,
- ) {}
- LaunchedEffect(state.currentValue) {
- if (state.currentValue == ModalBottomSheetValue.Hidden) {
- viewModel.onCancel()
}
+ } else {
+ SnackBarScreen(
+ onClick = viewModel::onMoreOptionOnSnackBarSelected,
+ onCancel = viewModel::onCancel,
+ )
}
}
@@ -173,7 +191,7 @@ fun PrimarySelectionCard(
color = Color.Transparent
)
Row(
- horizontalArrangement = Arrangement.Start,
+ horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
) {
CancelButton(stringResource(R.string.get_dialog_button_label_no_thanks), onCancel)
@@ -195,6 +213,8 @@ fun AllSignInOptionCard(
providerDisplayInfo: ProviderDisplayInfo,
onEntrySelected: (EntryInfo) -> Unit,
onBackButtonClicked: () -> Unit,
+ onCancel: () -> Unit,
+ isNoAccount: Boolean,
) {
val sortedUserNameToCredentialEntryList =
providerDisplayInfo.sortedUserNameToCredentialEntryList
@@ -212,7 +232,7 @@ fun AllSignInOptionCard(
)
},
navigationIcon = {
- IconButton(onClick = onBackButtonClicked) {
+ IconButton(onClick = if (isNoAccount) onCancel else onBackButtonClicked) {
Icon(
Icons.Filled.ArrowBack,
contentDescription = stringResource(
@@ -405,11 +425,12 @@ fun CredentialEntryRow(
Entry(
onClick = { onEntrySelected(credentialEntryInfo) },
icon = {
- Image(
+ Icon(
modifier = Modifier.padding(start = 10.dp).size(32.dp),
bitmap = credentialEntryInfo.icon.toBitmap().asImageBitmap(),
// TODO: add description.
- contentDescription = ""
+ contentDescription = "",
+ tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
)
},
label = {
@@ -418,19 +439,24 @@ fun CredentialEntryRow(
TextOnSurfaceVariant(
text = credentialEntryInfo.userName,
style = MaterialTheme.typography.titleLarge,
- modifier = Modifier.padding(top = 16.dp)
+ modifier = Modifier.padding(top = 16.dp, start = 5.dp)
)
TextSecondary(
- text =
- if (TextUtils.isEmpty(credentialEntryInfo.displayName))
- credentialEntryInfo.credentialTypeDisplayName
- else
- credentialEntryInfo.credentialTypeDisplayName +
- stringResource(
- R.string.get_dialog_sign_in_type_username_separator) +
- credentialEntryInfo.displayName,
+ text = if (
+ credentialEntryInfo.credentialType == Credential.TYPE_PASSWORD_CREDENTIAL) {
+ "••••••••••••"
+ } else {
+ if (TextUtils.isEmpty(credentialEntryInfo.displayName))
+ credentialEntryInfo.credentialTypeDisplayName
+ else
+ credentialEntryInfo.credentialTypeDisplayName +
+ stringResource(
+ R.string.get_dialog_sign_in_type_username_separator
+ ) +
+ credentialEntryInfo.displayName
+ },
style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp)
+ modifier = Modifier.padding(bottom = 16.dp, start = 5.dp)
)
}
}
@@ -454,17 +480,27 @@ fun AuthenticationEntryRow(
)
},
label = {
- Column() {
- // TODO: fix the text values.
- TextOnSurfaceVariant(
- text = authenticationEntryInfo.title,
- style = MaterialTheme.typography.titleLarge,
- modifier = Modifier.padding(top = 16.dp)
- )
- TextSecondary(
- text = stringResource(R.string.locked_credential_entry_label_subtext),
- style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(bottom = 16.dp)
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier.fillMaxWidth().padding(horizontal = 5.dp),
+ ) {
+ Column() {
+ // TODO: fix the text values.
+ TextOnSurfaceVariant(
+ text = authenticationEntryInfo.title,
+ style = MaterialTheme.typography.titleLarge,
+ modifier = Modifier.padding(top = 16.dp)
+ )
+ TextSecondary(
+ text = stringResource(R.string.locked_credential_entry_label_subtext),
+ style = MaterialTheme.typography.bodyMedium,
+ modifier = Modifier.padding(bottom = 16.dp)
+ )
+ }
+ Icon(
+ Icons.Outlined.Lock,
+ null,
+ Modifier.align(alignment = Alignment.CenterVertically).padding(end = 10.dp),
)
}
}
@@ -491,11 +527,13 @@ fun ActionEntryRow(
TextOnSurfaceVariant(
text = actionEntryInfo.title,
style = MaterialTheme.typography.titleLarge,
+ modifier = Modifier.padding(start = 5.dp),
)
if (actionEntryInfo.subTitle != null) {
TextSecondary(
text = actionEntryInfo.subTitle,
style = MaterialTheme.typography.bodyMedium,
+ modifier = Modifier.padding(start = 5.dp),
)
}
}
@@ -518,3 +556,37 @@ fun SignInAnotherWayRow(onSelect: () -> Unit) {
}
)
}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun SnackBarScreen(
+ onClick: (Boolean) -> Unit,
+ onCancel: () -> Unit,
+) {
+ // TODO: Change the height, width and position according to the design
+ Snackbar (
+ modifier = Modifier.padding(horizontal = 80.dp).padding(top = 700.dp),
+ shape = EntryShape.FullMediumRoundedCorner,
+ containerColor = LocalAndroidColorScheme.current.colorBackground,
+ contentColor = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ TextButton(
+ onClick = {onClick(true)},
+ ) {
+ Text(text = stringResource(R.string.get_dialog_use_saved_passkey_for))
+ }
+ IconButton(onClick = onCancel) {
+ Icon(
+ Icons.Filled.Close,
+ contentDescription = stringResource(
+ R.string.accessibility_close_button
+ )
+ )
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index 7b80124d618c..c182397b8aec 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -36,12 +36,13 @@ import com.android.internal.util.Preconditions
data class GetCredentialUiState(
val providerInfoList: List<ProviderInfo>,
- val currentScreenState: GetScreenState,
val requestDisplayInfo: RequestDisplayInfo,
+ val currentScreenState: GetScreenState = toGetScreenState(providerInfoList),
val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
val selectedEntry: EntryInfo? = null,
val hidden: Boolean = false,
val providerActivityPending: Boolean = false,
+ val isNoAccount: Boolean = false,
)
class GetCredentialViewModel(
@@ -127,6 +128,14 @@ class GetCredentialViewModel(
)
}
+ fun onMoreOptionOnSnackBarSelected(isNoAccount: Boolean) {
+ Log.d("Account Selector", "More Option on snackBar selected")
+ uiState = uiState.copy(
+ currentScreenState = GetScreenState.ALL_SIGN_IN_OPTIONS,
+ isNoAccount = isNoAccount,
+ )
+ }
+
fun onBackToPrimarySelectionScreen() {
uiState = uiState.copy(
currentScreenState = GetScreenState.PRIMARY_SELECTION
@@ -192,9 +201,36 @@ private fun toProviderDisplayInfo(
)
}
+private fun toGetScreenState(
+ providerInfoList: List<ProviderInfo>
+): GetScreenState {
+ var noLocalAccount = true
+ var remoteInfo: RemoteEntryInfo? = null
+ providerInfoList.forEach{providerInfo -> if (
+ providerInfo.credentialEntryList.isNotEmpty() || providerInfo.authenticationEntry != null
+ ) { noLocalAccount = false }
+ // TODO: handle the error situation that if multiple remoteInfos exists
+ if (providerInfo.remoteEntry != null) {
+ remoteInfo = providerInfo.remoteEntry
+ }
+ }
+
+ return if (noLocalAccount && remoteInfo != null)
+ GetScreenState.REMOTE_ONLY else GetScreenState.PRIMARY_SELECTION
+}
+
internal class CredentialEntryInfoComparator : Comparator<CredentialEntryInfo> {
override fun compare(p0: CredentialEntryInfo, p1: CredentialEntryInfo): Int {
- // First order by last used timestamp
+ // First prefer passkey type for its security benefits
+ if (p0.credentialType != p1.credentialType) {
+ if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p0.credentialType) {
+ return -1
+ } else if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p1.credentialType) {
+ return 1
+ }
+ }
+
+ // Then order by last used timestamp
if (p0.lastUsedTimeMillis != null && p1.lastUsedTimeMillis != null) {
if (p0.lastUsedTimeMillis < p1.lastUsedTimeMillis) {
return 1
@@ -206,15 +242,6 @@ internal class CredentialEntryInfoComparator : Comparator<CredentialEntryInfo> {
} else if (p1.lastUsedTimeMillis != null && p1.lastUsedTimeMillis > 0) {
return 1
}
-
- // Then prefer passkey type for its security benefits
- if (p0.credentialType != p1.credentialType) {
- if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p0.credentialType) {
- return -1
- } else if (PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL == p1.credentialType) {
- return 1
- }
- }
return 0
}
} \ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 0c3baffd8864..3a2a73801d8e 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -120,4 +120,6 @@ enum class GetScreenState {
PRIMARY_SELECTION,
/** The secondary credential selection page, where all sign-in options are listed. */
ALL_SIGN_IN_OPTIONS,
+ /** The snackbar only page when there's no account but only a remoteEntry. */
+ REMOTE_ONLY,
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt
index 1e639fe6bd55..19c5c2dfa4fe 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt
@@ -18,7 +18,6 @@ package com.android.credentialmanager.jetpack.provider
import android.app.slice.Slice
import android.credentials.ui.Entry
-import android.graphics.drawable.Icon
/**
* UI representation for a credential entry used during the get credential flow.
@@ -26,28 +25,24 @@ import android.graphics.drawable.Icon
* TODO: move to jetpack.
*/
class ActionUi(
- val icon: Icon,
val text: CharSequence,
val subtext: CharSequence?,
) {
companion object {
fun fromSlice(slice: Slice): ActionUi {
- var icon: Icon? = null
var text: CharSequence? = null
var subtext: CharSequence? = null
val items = slice.items
items.forEach {
- if (it.hasHint(Entry.HINT_ACTION_ICON)) {
- icon = it.icon
- } else if (it.hasHint(Entry.HINT_ACTION_TITLE)) {
+ if (it.hasHint(Entry.HINT_ACTION_TITLE)) {
text = it.text
} else if (it.hasHint(Entry.HINT_ACTION_SUBTEXT)) {
subtext = it.text
}
}
// TODO: fail NPE more elegantly.
- return ActionUi(icon!!, text!!, subtext)
+ return ActionUi(text!!, subtext)
}
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt
index 1693eb629b1b..47b5af0d7fe6 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt
@@ -16,8 +16,8 @@
package com.android.credentialmanager.jetpack.provider
+import android.app.PendingIntent
import android.app.slice.Slice
-import android.credentials.ui.Entry
import android.graphics.drawable.Icon
/**
@@ -32,38 +32,57 @@ class CredentialEntryUi(
val userDisplayName: CharSequence?,
val entryIcon: Icon?,
val lastUsedTimeMillis: Long?,
+ // TODO: Remove note
val note: CharSequence?,
) {
companion object {
+ // Copied over from jetpack
+ const val SLICE_HINT_TYPE_DISPLAY_NAME =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_TYPE_DISPLAY_NAME"
+ const val SLICE_HINT_USERNAME =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_USER_NAME"
+ const val SLICE_HINT_DISPLAYNAME =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_CREDENTIAL_TYPE_DISPLAY_NAME"
+ const val SLICE_HINT_LAST_USED_TIME_MILLIS =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_LAST_USED_TIME_MILLIS"
+ const val SLICE_HINT_ICON =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PROFILE_ICON"
+ const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PENDING_INTENT"
+
+ /**
+ * Returns an instance of [CredentialEntryUi] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through jetpack library
+ */
+ @JvmStatic
fun fromSlice(slice: Slice): CredentialEntryUi {
- var credentialType = slice.spec!!.type
- var credentialTypeDisplayName: CharSequence? = null
- var userName: CharSequence? = null
- var userDisplayName: CharSequence? = null
- var entryIcon: Icon? = null
- var lastUsedTimeMillis: Long? = null
+ var username: CharSequence? = null
+ var displayName: CharSequence = ""
+ var icon: Icon? = null
+ var pendingIntent: PendingIntent? = null
+ var lastUsedTimeMillis: Long = 0
var note: CharSequence? = null
+ var typeDisplayName: CharSequence = ""
- val items = slice.items
- items.forEach {
- if (it.hasHint(Entry.HINT_CREDENTIAL_TYPE_DISPLAY_NAME)) {
- credentialTypeDisplayName = it.text
- } else if (it.hasHint(Entry.HINT_USER_NAME)) {
- userName = it.text
- } else if (it.hasHint(Entry.HINT_PASSKEY_USER_DISPLAY_NAME)) {
- userDisplayName = it.text
- } else if (it.hasHint(Entry.HINT_PROFILE_ICON)) {
- entryIcon = it.icon
- } else if (it.hasHint(Entry.HINT_LAST_USED_TIME_MILLIS)) {
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_TYPE_DISPLAY_NAME)) {
+ typeDisplayName = it.text
+ } else if (it.hasHint(SLICE_HINT_USERNAME)) {
+ username = it.text
+ } else if (it.hasHint(SLICE_HINT_DISPLAYNAME)) {
+ displayName = it.text
+ } else if (it.hasHint(SLICE_HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ } else if (it.hasHint(SLICE_HINT_LAST_USED_TIME_MILLIS)) {
lastUsedTimeMillis = it.long
- } else if (it.hasHint(Entry.HINT_NOTE)) {
- note = it.text
}
}
-
return CredentialEntryUi(
- credentialType, credentialTypeDisplayName!!, userName!!, userDisplayName, entryIcon,
- lastUsedTimeMillis, note,
+ slice.spec!!.type, typeDisplayName, username!!, displayName, icon,
+ lastUsedTimeMillis, note,
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt
index bcc05315cfc0..313f0f97e246 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt
@@ -16,8 +16,8 @@
package com.android.credentialmanager.jetpack.provider
+import android.app.PendingIntent
import android.app.slice.Slice
-import android.credentials.ui.Entry
import android.graphics.drawable.Icon
/**
@@ -35,38 +35,45 @@ class SaveEntryUi(
val lastUsedTimeMillis: Long?,
) {
companion object {
- fun fromSlice(slice: Slice): SaveEntryUi {
- var userProviderAccountName: CharSequence? = null
- var credentialTypeIcon: Icon? = null
- var profileIcon: Icon? = null
- var passwordCount: Int? = null
- var passkeyCount: Int? = null
- var totalCredentialCount: Int? = null
- var lastUsedTimeMillis: Long? = null
+ const val SLICE_HINT_ACCOUNT_NAME =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_USER_PROVIDER_ACCOUNT_NAME"
+ const val SLICE_HINT_ICON =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_PROFILE_ICON"
+ const val SLICE_HINT_CREDENTIAL_COUNT_INFORMATION =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_CREDENTIAL_COUNT_INFORMATION"
+ const val SLICE_HINT_LAST_USED_TIME_MILLIS =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_LAST_USED_TIME_MILLIS"
+ const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_PENDING_INTENT"
+ /**
+ * Returns an instance of [SaveEntryUi] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through the jetpack library
+ */
+ @JvmStatic
+ fun fromSlice(slice: Slice): SaveEntryUi {
+ var accountName: CharSequence? = null
+ var icon: Icon? = null
+ var pendingIntent: PendingIntent? = null
+ var lastUsedTimeMillis: Long = 0
- val items = slice.items
- items.forEach {
- if (it.hasHint(Entry.HINT_USER_PROVIDER_ACCOUNT_NAME)) {
- userProviderAccountName = it.text
- } else if (it.hasHint(Entry.HINT_CREDENTIAL_TYPE_ICON)) {
- credentialTypeIcon = it.icon
- } else if (it.hasHint(Entry.HINT_PROFILE_ICON)) {
- profileIcon = it.icon
- } else if (it.hasHint(Entry.HINT_PASSWORD_COUNT)) {
- passwordCount = it.int
- } else if (it.hasHint(Entry.HINT_PASSKEY_COUNT)) {
- passkeyCount = it.int
- } else if (it.hasHint(Entry.HINT_TOTAL_CREDENTIAL_COUNT)) {
- totalCredentialCount = it.int
- } else if (it.hasHint(Entry.HINT_LAST_USED_TIME_MILLIS)) {
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_ACCOUNT_NAME)) {
+ accountName = it.text
+ } else if (it.hasHint(SLICE_HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ } else if (it.hasHint(SLICE_HINT_LAST_USED_TIME_MILLIS)) {
lastUsedTimeMillis = it.long
}
}
- // TODO: fail NPE more elegantly.
+
return SaveEntryUi(
- userProviderAccountName!!, credentialTypeIcon, profileIcon,
- passwordCount, passkeyCount, totalCredentialCount, lastUsedTimeMillis,
+ // TODO: Add count parsing
+ accountName!!, icon, icon,
+ 0, 0, 0, lastUsedTimeMillis,
)
}
}
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index a346cb2c1b2d..4ee4323daebd 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -56,6 +56,7 @@
<string name="print_select_printer" msgid="7388760939873368698">"Selecciona una impressora"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Oblida la impressora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other">S\'han trobat <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
<item quantity="one">S\'ha trobat <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
</plurals>
@@ -76,6 +77,7 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Serveis desactivats"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tots els serveis"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Instal·la\'l per detectar <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
<item quantity="one">Instal·la\'l per detectar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
</plurals>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 2ed8b7f1b0c5..4c93df72edb9 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -56,10 +56,9 @@
<string name="print_select_printer" msgid="7388760939873368698">"בחירת מדפסת"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"לשכוח את המדפסת"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="one">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
<item quantity="two">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
- <item quantity="many">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
<item quantity="other">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
- <item quantity="one">נמצאה מדפסת <xliff:g id="COUNT_0">%1$s</xliff:g></item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"מידע נוסף על המדפסת הזו"</string>
@@ -78,10 +77,9 @@
<string name="disabled_services_title" msgid="7313253167968363211">"שירותים מושבתים"</string>
<string name="all_services_title" msgid="5578662754874906455">"כל השירותים"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">יש להתקין כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
<item quantity="two">יש להתקין כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
- <item quantity="many">יש להתקין כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
<item quantity="other">יש להתקין כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
- <item quantity="one">יש להתקין כדי לגלות מדפסת אחת (<xliff:g id="COUNT_0">%1$s</xliff:g>)‏</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"בתהליך הדפסה של <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"המערכת מבטלת את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index 122f60672b2a..af7b8b4ccfc0 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -23,5 +23,6 @@ android_library {
apex_available: [
"//apex_available:platform",
"com.android.permission",
+ "com.android.healthconnect",
],
}
diff --git a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
index d32d65906efb..965fdcfd6f98 100644
--- a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
+++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
@@ -38,7 +38,12 @@
<provider
android:name="com.android.settingslib.spa.search.SpaSearchProvider"
android:authorities="com.android.spa.gallery.search.provider"
- android:exported="false">
+ android:exported="true"
+ android:grantUriPermissions="true"
+ android:permission="android.permission.READ_SEARCH_INDEXABLES">
+ <intent-filter>
+ <action android:name="android.content.action.SPA_SEARCH_PROVIDER" />
+ </intent-filter>
</provider>
<provider android:name="com.android.settingslib.spa.slice.SpaSliceProvider"
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index db4990974e23..e54e2764bb40 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -17,7 +17,7 @@
package com.android.settingslib.spa.gallery
import android.content.Context
-import com.android.settingslib.spa.framework.common.LocalLogger
+import com.android.settingslib.spa.debug.DebugLogger
import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
import com.android.settingslib.spa.framework.common.SpaEnvironment
import com.android.settingslib.spa.framework.common.createSettingsPage
@@ -83,7 +83,7 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) {
)
}
- override val logger = LocalLogger()
+ override val logger = DebugLogger()
override val browseActivityClass = GalleryMainActivity::class.java
override val sliceBroadcastReceiverClass = SpaSliceBroadcastReceiver::class.java
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/dark_landscape_preference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/dark_landscape_preference.png
deleted file mode 100644
index 6086e2d15dd2..000000000000
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/dark_landscape_preference.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/dark_portrait_preference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/dark_portrait_preference.png
deleted file mode 100644
index aa6c5b7cd131..000000000000
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/dark_portrait_preference.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.png
new file mode 100644
index 000000000000..74113d8e41b8
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.png
new file mode 100644
index 000000000000..0d22c6a7d9e4
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.png
new file mode 100644
index 000000000000..f77b8a78d174
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.png
new file mode 100644
index 000000000000..93727915b2d9
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.png
new file mode 100644
index 000000000000..dda9e9e88932
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.png
new file mode 100644
index 000000000000..bf19a2c5b77e
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.png
new file mode 100644
index 000000000000..b14e196ea007
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png
index cac990caad63..c77f9b182140 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
new file mode 100644
index 000000000000..6bf20bedecba
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.png
new file mode 100644
index 000000000000..dda6f0a48d20
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.png
new file mode 100644
index 000000000000..7468169c3be1
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.png
new file mode 100644
index 000000000000..669f443fcd5c
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.png
new file mode 100644
index 000000000000..8e37cc0e11d9
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.png
new file mode 100644
index 000000000000..b0543e0c0641
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.png
new file mode 100644
index 000000000000..375592899fac
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.png
new file mode 100644
index 000000000000..f77b8a78d174
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.png
new file mode 100644
index 000000000000..7800149c36ee
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.png
new file mode 100644
index 000000000000..be409599b084
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.png
new file mode 100644
index 000000000000..2d5894e98dc0
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.png
new file mode 100644
index 000000000000..2a54b9e50703
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png
index f6298c0b62c4..b0fc305fd23f 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
new file mode 100644
index 000000000000..fa01348108a5
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.png
new file mode 100644
index 000000000000..213c0b243b8b
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.png
new file mode 100644
index 000000000000..7468169c3be1
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.png
new file mode 100644
index 000000000000..ce7ab78e56fa
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.png
new file mode 100644
index 000000000000..9d92f7ac9ac9
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_landscape_preference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_landscape_preference.png
deleted file mode 100644
index 9391eeb01e74..000000000000
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_landscape_preference.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.png
new file mode 100644
index 000000000000..5255d14bc4b5
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.png
new file mode 100644
index 000000000000..8f3f664536b3
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.png
new file mode 100644
index 000000000000..cc1de5520d15
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.png
new file mode 100644
index 000000000000..e29f26aed3aa
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.png
new file mode 100644
index 000000000000..8b9bc5cb85c3
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.png
new file mode 100644
index 000000000000..b1676b3e01ab
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.png
new file mode 100644
index 000000000000..2a7b34161960
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png
index 94e28437c04e..4845ea8f32e9 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
new file mode 100644
index 000000000000..7e579583051a
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.png
new file mode 100644
index 000000000000..d1abaa6952ea
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.png
new file mode 100644
index 000000000000..c211e0e20c69
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.png
new file mode 100644
index 000000000000..9c57e332b2c9
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.png
new file mode 100644
index 000000000000..d416a0bbf3e0
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/light_landscape_preference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/light_landscape_preference.png
deleted file mode 100644
index b1d03c31362e..000000000000
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/light_landscape_preference.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/light_portrait_preference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/light_portrait_preference.png
deleted file mode 100644
index 95f19da3c52c..000000000000
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/light_portrait_preference.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/res/drawable/accessibility_captioning_banner.xml b/packages/SettingsLib/Spa/screenshot/res/drawable/accessibility_captioning_banner.xml
new file mode 100644
index 000000000000..6597ffb57688
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/res/drawable/accessibility_captioning_banner.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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <path
+ android:pathData="M383.9,300H28.1C12.6,300 0,287.4 0,271.9V28.1C0,12.6 12.6,0 28.1,0h355.8C399.4,0 412,12.6 412,28.1v243.8C412,287.4 399.4,300 383.9,300z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M79.2,179.6h53.6v8.5h-53.6z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M142.5,179.6h30.4v8.5h-30.4z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M79.2,195.5h79.2v8.5h-79.2z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M168.1,195.5h34.1v8.5h-34.1z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M211.9,195.5h34.1v8.5h-34.1z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M182.7,179.6h73.1v8.5h-73.1z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M265.5,179.6h26.8v8.5h-26.8z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M302.1,179.6h26.8v8.5h-26.8z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M142.7,67.9h-11.5c-1.6,0 -2.9,1.3 -2.9,2.9H67.8c-7.9,0 -14.4,6.5 -14.4,14.4v132.4c0,7.9 6.5,14.4 14.4,14.4h276.4c7.9,0 14.4,-6.5 14.4,-14.4V85.2c0,-7.9 -6.5,-14.4 -14.4,-14.4H203.1c0,-1.6 -1.3,-2.9 -2.9,-2.9h-28.8c-1.6,0 -2.9,1.3 -2.9,2.9h-23C145.5,69.2 144.3,67.9 142.7,67.9zM344.2,73.7c6.4,0 11.5,5.2 11.5,11.5v132.4c0,6.3 -5.2,11.5 -11.5,11.5H67.8c-6.4,0 -11.5,-5.2 -11.5,-11.5V85.2c0,-6.3 5.2,-11.5 11.5,-11.5H344.2z"
+ android:fillColor="#DADCE0"/>
+</vector>
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/button/ActionButtonsScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/button/ActionButtonsScreenshotTest.kt
new file mode 100644
index 000000000000..b2e0b181f88b
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/button/ActionButtonsScreenshotTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.material.icons.outlined.Launch
+import androidx.compose.material.icons.outlined.WarningAmber
+import com.android.settingslib.spa.widget.button.ActionButton
+import com.android.settingslib.spa.widget.button.ActionButtons
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class ActionButtonsScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("actionButtons") {
+ val actionButtons = listOf(
+ ActionButton(text = "Open", imageVector = Icons.Outlined.Launch) {},
+ ActionButton(text = "Uninstall", imageVector = Icons.Outlined.Delete) {},
+ ActionButton(text = "Force stop", imageVector = Icons.Outlined.WarningAmber) {},
+ )
+ ActionButtons(actionButtons)
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
new file mode 100644
index 000000000000..27d270c5d58e
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import com.android.settingslib.spa.widget.chart.BarChart
+import com.android.settingslib.spa.widget.chart.BarChartData
+import com.android.settingslib.spa.widget.chart.BarChartModel
+import com.github.mikephil.charting.formatter.IAxisValueFormatter
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class BarChartScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("barChart") {
+ BarChart(
+ barChartModel = object : BarChartModel {
+ override val chartDataList = listOf(
+ BarChartData(x = 0f, y = 12f),
+ BarChartData(x = 1f, y = 5f),
+ BarChartData(x = 2f, y = 21f),
+ BarChartData(x = 3f, y = 5f),
+ BarChartData(x = 4f, y = 10f),
+ BarChartData(x = 5f, y = 9f),
+ BarChartData(x = 6f, y = 1f),
+ )
+ override val xValueFormatter =
+ IAxisValueFormatter { value, _ ->
+ "${WeekDay.values()[value.toInt()]}"
+ }
+ override val yValueFormatter =
+ IAxisValueFormatter { value, _ ->
+ "${value.toInt()}m"
+ }
+ override val yAxisMaxValue = 30f
+ }
+ )
+ }
+ }
+
+ private enum class WeekDay(val num: Int) {
+ Sun(0), Mon(1), Tue(2), Wed(3), Thu(4), Fri(5), Sat(6),
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/LineChartScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/LineChartScreenshotTest.kt
new file mode 100644
index 000000000000..f9d93f878f2b
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/LineChartScreenshotTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import com.android.settingslib.spa.widget.chart.LineChart
+import com.android.settingslib.spa.widget.chart.LineChartData
+import com.android.settingslib.spa.widget.chart.LineChartModel
+import com.github.mikephil.charting.formatter.IAxisValueFormatter
+import java.text.NumberFormat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class LineChartScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("lineChart") {
+ LineChart(
+ lineChartModel = object : LineChartModel {
+ override val chartDataList = listOf(
+ LineChartData(x = 0f, y = 0f),
+ LineChartData(x = 1f, y = 0.1f),
+ LineChartData(x = 2f, y = 0.2f),
+ LineChartData(x = 3f, y = 0.6f),
+ LineChartData(x = 4f, y = 0.9f),
+ LineChartData(x = 5f, y = 1.0f),
+ LineChartData(x = 6f, y = 0.8f),
+ )
+ override val xValueFormatter =
+ IAxisValueFormatter { value, _ ->
+ "${WeekDay.values()[value.toInt()]}"
+ }
+ override val yValueFormatter =
+ IAxisValueFormatter { value, _ ->
+ NumberFormat.getPercentInstance().format(value)
+ }
+ }
+ )
+ }
+ }
+
+ private enum class WeekDay(val num: Int) {
+ Sun(0), Mon(1), Tue(2), Wed(3), Thu(4), Fri(5), Sat(6),
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/PieChartScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/PieChartScreenshotTest.kt
new file mode 100644
index 000000000000..34ded3cb94d6
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/PieChartScreenshotTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import com.android.settingslib.spa.widget.chart.PieChart
+import com.android.settingslib.spa.widget.chart.PieChartData
+import com.android.settingslib.spa.widget.chart.PieChartModel
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class PieChartScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("pieChart") {
+ PieChart(
+ pieChartModel = object : PieChartModel {
+ override val chartDataList = listOf(
+ PieChartData(label = "Settings", value = 20f),
+ PieChartData(label = "Chrome", value = 5f),
+ PieChartData(label = "Gmail", value = 3f),
+ )
+ override val centerText = "Today"
+ }
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/illustration/ImageIllustrationScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/illustration/ImageIllustrationScreenshotTest.kt
new file mode 100644
index 000000000000..91aca05a9cdf
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/illustration/ImageIllustrationScreenshotTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import com.android.settingslib.spa.widget.illustration.Illustration
+import com.android.settingslib.spa.widget.illustration.IllustrationModel
+import com.android.settingslib.spa.widget.illustration.ResourceType
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class ImageIllustrationScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("imageIllustration") {
+ Illustration(object : IllustrationModel {
+ override val resId = R.drawable.accessibility_captioning_banner
+ override val resourceType = ResourceType.IMAGE
+ })
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/MainSwitchPreferenceScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/MainSwitchPreferenceScreenshotTest.kt
new file mode 100644
index 000000000000..a366b9e0e85b
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/MainSwitchPreferenceScreenshotTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import androidx.compose.foundation.layout.Column
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.widget.preference.MainSwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class MainSwitchPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("mainSwitchPreference") {
+ Column {
+ MainSwitchPreference(
+ object : SwitchPreferenceModel {
+ override val title = "MainSwitchPreference"
+ override val checked = stateOf(false)
+ override val onCheckedChange = null
+ })
+
+ MainSwitchPreference(object : SwitchPreferenceModel {
+ override val title = "Not changeable"
+ override val changeable = stateOf(false)
+ override val checked = stateOf(true)
+ override val onCheckedChange = null
+ })
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/PreferenceScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/PreferenceScreenshotTest.kt
index 963182638293..d72152c15af2 100644
--- a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/PreferenceScreenshotTest.kt
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/PreferenceScreenshotTest.kt
@@ -16,6 +16,7 @@
package com.android.settingslib.spa.screenshot
+import androidx.compose.foundation.layout.Column
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Autorenew
import androidx.compose.material.icons.outlined.DisabledByDefault
@@ -23,7 +24,6 @@ import androidx.compose.runtime.Composable
import com.android.settingslib.spa.framework.compose.toState
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.SettingsIcon
import org.junit.Rule
import org.junit.Test
@@ -37,7 +37,7 @@ class PreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletFull
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
private const val TITLE = "Title"
private const val SUMMARY = "Summary"
private const val LONG_SUMMARY =
@@ -52,9 +52,9 @@ class PreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
)
@Test
- fun testPreference() {
+ fun test() {
screenshotRule.screenshotTest("preference") {
- RegularScaffold(title = "Preference") {
+ Column {
Preference(object : PreferenceModel {
override val title = TITLE
})
@@ -88,4 +88,4 @@ class PreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
}
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/ProgressBarPreferenceScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/ProgressBarPreferenceScreenshotTest.kt
new file mode 100644
index 000000000000..5fcaf8503095
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/ProgressBarPreferenceScreenshotTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.material.icons.outlined.SystemUpdate
+import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.widget.preference.ProgressBarPreference
+import com.android.settingslib.spa.widget.preference.ProgressBarPreferenceModel
+import com.android.settingslib.spa.widget.preference.ProgressBarWithDataPreference
+import com.android.settingslib.spa.widget.ui.CircularProgressBar
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class ProgressBarPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("progressBar") {
+ Column {
+ LargeProgressBar()
+ SimpleProgressBar()
+ ProgressBarWithData()
+ CircularProgressBar(progress = 0.8f, radius = 160f)
+ }
+ }
+ }
+}
+
+@Composable
+private fun LargeProgressBar() {
+ ProgressBarPreference(object : ProgressBarPreferenceModel {
+ override val title = "Large Progress Bar"
+ override val progress = 0.2f
+ override val height = 20f
+ })
+}
+
+@Composable
+private fun SimpleProgressBar() {
+ ProgressBarPreference(object : ProgressBarPreferenceModel {
+ override val title = "Simple Progress Bar"
+ override val progress = 0.2f
+ override val icon = Icons.Outlined.SystemUpdate
+ })
+}
+
+@Composable
+private fun ProgressBarWithData() {
+ ProgressBarWithDataPreference(model = object : ProgressBarPreferenceModel {
+ override val title = "Progress Bar with Data"
+ override val progress = 0.2f
+ override val icon = Icons.Outlined.Delete
+ }, data = "25G")
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt
new file mode 100644
index 000000000000..48c922dcf1a1
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.AccessAlarm
+import com.android.settingslib.spa.widget.preference.SliderPreference
+import com.android.settingslib.spa.widget.preference.SliderPreferenceModel
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class SliderPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("slider") {
+ Column {
+ SliderPreference(object : SliderPreferenceModel {
+ override val title = "Simple Slider"
+ override val initValue = 40
+ })
+
+ SliderPreference(object : SliderPreferenceModel {
+ override val title = "Slider with icon"
+ override val initValue = 30
+ override val onValueChangeFinished = {
+ println("onValueChangeFinished")
+ }
+ override val icon = Icons.Outlined.AccessAlarm
+ })
+
+ SliderPreference(object : SliderPreferenceModel {
+ override val title = "Slider with steps"
+ override val initValue = 2
+ override val valueRange = 1..5
+ override val showSteps = true
+ })
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SwitchPreferenceScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SwitchPreferenceScreenshotTest.kt
new file mode 100644
index 000000000000..2c84a8e3f760
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SwitchPreferenceScreenshotTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.AirplanemodeActive
+import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.widget.preference.SwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spa.widget.ui.SettingsIcon
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class SwitchPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("switchPreference") {
+ Column {
+ SampleSwitchPreference()
+ SampleSwitchPreferenceWithSummary()
+ SampleNotChangeableSwitchPreference()
+ SampleSwitchPreferenceWithIcon()
+ }
+ }
+ }
+}
+
+@Composable
+private fun SampleSwitchPreference() {
+ SwitchPreference(object : SwitchPreferenceModel {
+ override val title = "SwitchPreference"
+ override val checked = stateOf(false)
+ override val onCheckedChange = null
+ })
+}
+
+@Composable
+private fun SampleSwitchPreferenceWithSummary() {
+ SwitchPreference(object : SwitchPreferenceModel {
+ override val title = "SwitchPreference"
+ override val summary = stateOf("With summary")
+ override val checked = stateOf(true)
+ override val onCheckedChange = null
+ })
+}
+
+@Composable
+private fun SampleNotChangeableSwitchPreference() {
+ SwitchPreference(object : SwitchPreferenceModel {
+ override val title = "SwitchPreference"
+ override val summary = stateOf("Not changeable")
+ override val changeable = stateOf(false)
+ override val checked = stateOf(true)
+ override val onCheckedChange = null
+ })
+}
+
+@Composable
+private fun SampleSwitchPreferenceWithIcon() {
+ SwitchPreference(object : SwitchPreferenceModel {
+ override val title = "SwitchPreference"
+ override val checked = stateOf(true)
+ override val onCheckedChange = null
+ override val icon = @Composable {
+ SettingsIcon(imageVector = Icons.Outlined.AirplanemodeActive)
+ }
+ })
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/TwoTargetSwitchPreferenceScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/TwoTargetSwitchPreferenceScreenshotTest.kt
new file mode 100644
index 000000000000..2c37212f1a71
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/TwoTargetSwitchPreferenceScreenshotTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import androidx.compose.foundation.layout.Column
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class TwoTargetSwitchPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("twoTargetSwitchPreference") {
+ Column {
+ TwoTargetSwitchPreference(object : SwitchPreferenceModel {
+ override val title = "TwoTargetSwitchPreference"
+ override val checked = stateOf(false)
+ override val onCheckedChange = null
+ }) {}
+
+ TwoTargetSwitchPreference(object : SwitchPreferenceModel {
+ override val title = "TwoTargetSwitchPreference"
+ override val summary = stateOf("With summary")
+ override val checked = stateOf(true)
+ override val onCheckedChange = null
+ }) {}
+
+ TwoTargetSwitchPreference(object : SwitchPreferenceModel {
+ override val title = "Not changeable"
+ override val changeable = stateOf(false)
+ override val checked = stateOf(true)
+ override val onCheckedChange = null
+ }) {}
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/FooterScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/FooterScreenshotTest.kt
new file mode 100644
index 000000000000..0a0faf6dd2c7
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/FooterScreenshotTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import com.android.settingslib.spa.widget.ui.Footer
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class FooterScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("footer") {
+ Footer(footerText = "Footer text always at the end of page.")
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/SpinnerScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/SpinnerScreenshotTest.kt
new file mode 100644
index 000000000000..e9b5b306fc0a
--- /dev/null
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/ui/SpinnerScreenshotTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.screenshot
+
+import com.android.settingslib.spa.widget.ui.Spinner
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import platform.test.screenshot.DeviceEmulationSpec
+
+/** A screenshot test for ExampleFeature. */
+@RunWith(Parameterized::class)
+class SpinnerScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() = DeviceEmulationSpec.PhoneAndTabletMinimal
+ }
+
+ @get:Rule
+ val screenshotRule =
+ SettingsScreenshotTestRule(
+ emulationSpec,
+ "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
+ )
+
+ @Test
+ fun test() {
+ screenshotRule.screenshotTest("spinner") {
+ Spinner(
+ options = (1..3).map { "Option $it" },
+ selectedIndex = 0,
+ setIndex = {},
+ )
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp
index 3ea3b5ccc4f5..40613ceaaf5f 100644
--- a/packages/SettingsLib/Spa/spa/Android.bp
+++ b/packages/SettingsLib/Spa/spa/Android.bp
@@ -44,3 +44,9 @@ android_library {
],
min_sdk_version: "31",
}
+
+// Expose the srcs to tests, so the tests can access the internal classes.
+filegroup {
+ name: "SpaLib_srcs",
+ srcs: ["src/**/*.kt"],
+}
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 19963fbeed82..85ac8ec8e00d 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -108,6 +108,17 @@ task coverageReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest")
// Excludes files forked from Accompanist.
"com/android/settingslib/spa/framework/compose/DrawablePainter*",
"com/android/settingslib/spa/framework/compose/Pager*",
+
+ // Excludes inline functions, which is not covered in Jacoco reports.
+ "com/android/settingslib/spa/framework/util/Collections*",
+ "com/android/settingslib/spa/framework/util/Flows*",
+
+ // Excludes debug functions
+ "com/android/settingslib/spa/framework/compose/TimeMeasurer*",
+
+ // Excludes slice demo presenter & provider
+ "com/android/settingslib/spa/slice/presenter/Demo*",
+ "com/android/settingslib/spa/slice/provider/Demo*",
],
)
executionData.from = fileTree(dir: "$buildDir/outputs/code_coverage/debugAndroidTest/connected")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugLogger.kt
new file mode 100644
index 000000000000..7d4833635f9d
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugLogger.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.debug
+
+import android.os.Bundle
+import android.util.Log
+import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SpaLogger
+
+class DebugLogger : SpaLogger {
+ override fun message(tag: String, msg: String, category: LogCategory) {
+ Log.d("SpaMsg-$category", "[$tag] $msg")
+ }
+
+ override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
+ val extraMsg = extraData.toString().removeRange(0, 6)
+ Log.d("SpaEvent-$category", "[$id] $event $extraMsg")
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index 4985b44783e9..0871304fa873 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -25,8 +25,8 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import com.android.settingslib.spa.framework.compose.LocalNavController
-const val INJECT_ENTRY_NAME = "INJECT"
-const val ROOT_ENTRY_NAME = "ROOT"
+private const val INJECT_ENTRY_NAME = "INJECT"
+private const val ROOT_ENTRY_NAME = "ROOT"
interface EntryData {
val pageId: String?
@@ -151,7 +151,7 @@ data class SettingsEntry(
}
@Composable
- fun provideLocalEntryData(arguments: Bundle): ProvidedValue<EntryData> {
+ private fun provideLocalEntryData(arguments: Bundle): ProvidedValue<EntryData> {
val controller = LocalNavController.current
return LocalEntryDataProvider provides remember {
object : EntryData {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
index 6d0b810d0cb6..f672ee01d070 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
@@ -29,6 +29,10 @@ private const val TAG = "SpaEnvironment"
object SpaEnvironmentFactory {
private var spaEnvironment: SpaEnvironment? = null
+ fun reset() {
+ spaEnvironment = null
+ }
+
fun reset(env: SpaEnvironment) {
spaEnvironment = env
Log.d(TAG, "reset")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
index 6ecb7fa94c3c..78df0f27cc6a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
@@ -17,7 +17,6 @@
package com.android.settingslib.spa.framework.common
import android.os.Bundle
-import android.util.Log
// Defines the category of the log, for quick filter
enum class LogCategory {
@@ -62,14 +61,3 @@ interface SpaLogger {
) {
}
}
-
-class LocalLogger : SpaLogger {
- override fun message(tag: String, msg: String, category: LogCategory) {
- Log.d("SpaMsg-$category", "[$tag] $msg")
- }
-
- override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
- val extraMsg = extraData.toString().removeRange(0, 6)
- Log.d("SpaEvent-$category", "[$id] $event $extraMsg")
- }
-} \ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
index fa17e08e9885..d72ec264cf74 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
@@ -18,6 +18,7 @@ package com.android.settingslib.spa.framework.theme
import android.content.Context
import android.os.Build
+import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
@@ -64,7 +65,8 @@ internal fun settingsColorScheme(isDarkTheme: Boolean): SettingsColorScheme {
*
* @param context The context required to get system resource data.
*/
-private fun dynamicLightColorScheme(context: Context): SettingsColorScheme {
+@VisibleForTesting
+internal fun dynamicLightColorScheme(context: Context): SettingsColorScheme {
val tonalPalette = dynamicTonalPalette(context)
return SettingsColorScheme(
background = tonalPalette.neutral95,
@@ -90,7 +92,8 @@ private fun dynamicLightColorScheme(context: Context): SettingsColorScheme {
*
* @param context The context required to get system resource data.
*/
-private fun dynamicDarkColorScheme(context: Context): SettingsColorScheme {
+@VisibleForTesting
+internal fun dynamicDarkColorScheme(context: Context): SettingsColorScheme {
val tonalPalette = dynamicTonalPalette(context)
return SettingsColorScheme(
background = tonalPalette.neutral10,
@@ -107,7 +110,8 @@ private fun dynamicDarkColorScheme(context: Context): SettingsColorScheme {
)
}
-private fun darkColorScheme(): SettingsColorScheme {
+@VisibleForTesting
+internal fun darkColorScheme(): SettingsColorScheme {
val tonalPalette = tonalPalette()
return SettingsColorScheme(
background = tonalPalette.neutral10,
@@ -124,7 +128,8 @@ private fun darkColorScheme(): SettingsColorScheme {
)
}
-private fun lightColorScheme(): SettingsColorScheme {
+@VisibleForTesting
+internal fun lightColorScheme(): SettingsColorScheme {
val tonalPalette = tonalPalette()
return SettingsColorScheme(
background = tonalPalette.neutral95,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
index 2301f0485040..83dcd137fbd7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
@@ -33,6 +33,13 @@ const val SEARCH_IMMUTABLE_STATUS = "search_immutable_status"
/** ContentProvider path for search mutable status */
const val SEARCH_MUTABLE_STATUS = "search_mutable_status"
+/** ContentProvider path for search static row */
+const val SEARCH_STATIC_ROW = "search_static_row"
+
+/** ContentProvider path for search dynamic row */
+const val SEARCH_DYNAMIC_ROW = "search_dynamic_row"
+
+
/** Enum to define all column names in provider. */
enum class ColumnEnum(val id: String) {
ENTRY_ID("entryId"),
@@ -76,6 +83,7 @@ enum class QueryEnum(
ColumnEnum.SEARCH_PATH,
ColumnEnum.INTENT_TARGET_PACKAGE,
ColumnEnum.INTENT_TARGET_CLASS,
+ ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
ColumnEnum.LEGACY_KEY
)
@@ -94,4 +102,34 @@ enum class QueryEnum(
ColumnEnum.ENTRY_DISABLED,
)
),
+ SEARCH_STATIC_ROW_QUERY(
+ SEARCH_STATIC_ROW,
+ listOf(
+ ColumnEnum.ENTRY_ID,
+ ColumnEnum.SEARCH_TITLE,
+ ColumnEnum.SEARCH_KEYWORD,
+ ColumnEnum.SEARCH_PATH,
+ ColumnEnum.INTENT_TARGET_PACKAGE,
+ ColumnEnum.INTENT_TARGET_CLASS,
+ ColumnEnum.INTENT_EXTRAS,
+ ColumnEnum.SLICE_URI,
+ ColumnEnum.LEGACY_KEY,
+ ColumnEnum.ENTRY_DISABLED,
+ )
+ ),
+ SEARCH_DYNAMIC_ROW_QUERY(
+ SEARCH_DYNAMIC_ROW,
+ listOf(
+ ColumnEnum.ENTRY_ID,
+ ColumnEnum.SEARCH_TITLE,
+ ColumnEnum.SEARCH_KEYWORD,
+ ColumnEnum.SEARCH_PATH,
+ ColumnEnum.INTENT_TARGET_PACKAGE,
+ ColumnEnum.INTENT_TARGET_CLASS,
+ ColumnEnum.INTENT_EXTRAS,
+ ColumnEnum.SLICE_URI,
+ ColumnEnum.LEGACY_KEY,
+ ColumnEnum.ENTRY_DISABLED,
+ )
+ ),
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
index 21bc75a11942..057f13f99928 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
@@ -28,7 +28,6 @@ import android.os.Parcel
import android.os.Parcelable
import android.util.Log
import androidx.annotation.VisibleForTesting
-import com.android.settingslib.spa.framework.common.EntryStatusData
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
@@ -49,6 +48,8 @@ private const val TAG = "SpaSearchProvider"
* $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_data
* $ adb shell content query --uri content://<AuthorityPath>/search_immutable_status
* $ adb shell content query --uri content://<AuthorityPath>/search_mutable_status
+ * $ adb shell content query --uri content://<AuthorityPath>/search_static_row
+ * $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_row
*/
class SpaSearchProvider : ContentProvider() {
private val spaEnvironment get() = SpaEnvironmentFactory.instance
@@ -58,7 +59,9 @@ class SpaSearchProvider : ContentProvider() {
SEARCH_STATIC_DATA to 301,
SEARCH_DYNAMIC_DATA to 302,
SEARCH_MUTABLE_STATUS to 303,
- SEARCH_IMMUTABLE_STATUS to 304
+ SEARCH_IMMUTABLE_STATUS to 304,
+ SEARCH_STATIC_ROW to 305,
+ SEARCH_DYNAMIC_ROW to 306
)
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
@@ -114,6 +117,8 @@ class SpaSearchProvider : ContentProvider() {
querySearchMutableStatusData()
queryMatchCode[SEARCH_IMMUTABLE_STATUS] ->
querySearchImmutableStatusData()
+ queryMatchCode[SEARCH_STATIC_ROW] -> querySearchStaticRow()
+ queryMatchCode[SEARCH_DYNAMIC_ROW] -> querySearchDynamicRow()
else -> throw UnsupportedOperationException("Unknown Uri $uri")
}
} catch (e: UnsupportedOperationException) {
@@ -125,7 +130,7 @@ class SpaSearchProvider : ContentProvider() {
}
@VisibleForTesting
- fun querySearchImmutableStatusData(): Cursor {
+ internal fun querySearchImmutableStatusData(): Cursor {
val entryRepository by spaEnvironment.entryRepository
val cursor = MatrixCursor(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.getColumns())
for (entry in entryRepository.getAllEntries()) {
@@ -136,7 +141,7 @@ class SpaSearchProvider : ContentProvider() {
}
@VisibleForTesting
- fun querySearchMutableStatusData(): Cursor {
+ internal fun querySearchMutableStatusData(): Cursor {
val entryRepository by spaEnvironment.entryRepository
val cursor = MatrixCursor(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.getColumns())
for (entry in entryRepository.getAllEntries()) {
@@ -147,7 +152,7 @@ class SpaSearchProvider : ContentProvider() {
}
@VisibleForTesting
- fun querySearchStaticData(): Cursor {
+ internal fun querySearchStaticData(): Cursor {
val entryRepository by spaEnvironment.entryRepository
val cursor = MatrixCursor(QueryEnum.SEARCH_STATIC_DATA_QUERY.getColumns())
for (entry in entryRepository.getAllEntries()) {
@@ -158,7 +163,7 @@ class SpaSearchProvider : ContentProvider() {
}
@VisibleForTesting
- fun querySearchDynamicData(): Cursor {
+ internal fun querySearchDynamicData(): Cursor {
val entryRepository by spaEnvironment.entryRepository
val cursor = MatrixCursor(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.getColumns())
for (entry in entryRepository.getAllEntries()) {
@@ -168,6 +173,31 @@ class SpaSearchProvider : ContentProvider() {
return cursor
}
+ @VisibleForTesting
+ fun querySearchStaticRow(): Cursor {
+ val entryRepository by spaEnvironment.entryRepository
+ val cursor = MatrixCursor(QueryEnum.SEARCH_STATIC_ROW_QUERY.getColumns())
+ for (entry in entryRepository.getAllEntries()) {
+ if (!entry.isAllowSearch || entry.isSearchDataDynamic || entry.hasMutableStatus)
+ continue
+ fetchSearchRow(entry, cursor)
+ }
+ return cursor
+ }
+
+ @VisibleForTesting
+ fun querySearchDynamicRow(): Cursor {
+ val entryRepository by spaEnvironment.entryRepository
+ val cursor = MatrixCursor(QueryEnum.SEARCH_DYNAMIC_ROW_QUERY.getColumns())
+ for (entry in entryRepository.getAllEntries()) {
+ if (!entry.isAllowSearch || (!entry.isSearchDataDynamic && !entry.hasMutableStatus))
+ continue
+ fetchSearchRow(entry, cursor)
+ }
+ return cursor
+ }
+
+
private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) {
val entryRepository by spaEnvironment.entryRepository
@@ -196,12 +226,42 @@ class SpaSearchProvider : ContentProvider() {
private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
// Fetch status data. We can add runtime arguments later if necessary
- val statusData = entry.getStatusData() ?: EntryStatusData()
+ val statusData = entry.getStatusData() ?: return
cursor.newRow()
.add(ColumnEnum.ENTRY_ID.id, entry.id)
.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
}
+ private fun fetchSearchRow(entry: SettingsEntry, cursor: MatrixCursor) {
+ val entryRepository by spaEnvironment.entryRepository
+
+ // Fetch search data. We can add runtime arguments later if necessary
+ val searchData = entry.getSearchData() ?: return
+ val intent = entry.createIntent(SESSION_SEARCH)
+ val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
+ .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
+ .add(
+ ColumnEnum.SEARCH_PATH.id,
+ entryRepository.getEntryPathWithTitle(entry.id, searchData.title)
+ )
+ intent?.let {
+ row.add(ColumnEnum.INTENT_TARGET_PACKAGE.id, spaEnvironment.appContext.packageName)
+ .add(ColumnEnum.INTENT_TARGET_CLASS.id, spaEnvironment.browseActivityClass?.name)
+ .add(ColumnEnum.INTENT_EXTRAS.id, marshall(intent.extras))
+ }
+ if (entry.hasSliceSupport)
+ row.add(
+ ColumnEnum.SLICE_URI.id, Uri.Builder()
+ .fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
+ )
+ // TODO: support legacy key
+
+ // Fetch status data. We can add runtime arguments later if necessary
+ val statusData = entry.getStatusData() ?: return
+ row.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
+ }
+
private fun QueryEnum.getColumns(): Array<String> {
return columnNames.map { it.id }.toTypedArray()
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/provider/Demo.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/provider/Demo.kt
index 3d7d5659923c..e4a738631474 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/provider/Demo.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/provider/Demo.kt
@@ -19,12 +19,12 @@ package com.android.settingslib.spa.slice.provider
import android.app.PendingIntent
import android.content.Context
import android.net.Uri
+import androidx.core.R
import androidx.core.graphics.drawable.IconCompat
import androidx.slice.Slice
import androidx.slice.SliceManager
import androidx.slice.builders.ListBuilder
import androidx.slice.builders.SliceAction
-import androidx.slice.core.R
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.slice.createBroadcastPendingIntent
import com.android.settingslib.spa.slice.createBrowsePendingIntent
diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp
index 6974005819ea..f9e64aee1513 100644
--- a/packages/SettingsLib/Spa/tests/Android.bp
+++ b/packages/SettingsLib/Spa/tests/Android.bp
@@ -22,7 +22,10 @@ android_test {
name: "SpaLibTests",
test_suites: ["device-tests"],
- srcs: ["src/**/*.kt"],
+ srcs: [
+ ":SpaLib_srcs",
+ "src/**/*.kt",
+ ],
static_libs: [
"SpaLib",
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
index f98963c869de..b600ac6cd322 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
@@ -16,10 +16,13 @@
package com.android.settingslib.spa.framework.common
+import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.core.os.bundleOf
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.slice.appendSpaParams
+import com.android.settingslib.spa.slice.getEntryId
import com.android.settingslib.spa.tests.testutils.getUniqueEntryId
import com.android.settingslib.spa.tests.testutils.getUniquePageId
import com.google.common.truth.Truth.assertThat
@@ -27,8 +30,8 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-const val INJECT_ENTRY_NAME = "INJECT"
-const val ROOT_ENTRY_NAME = "ROOT"
+const val INJECT_ENTRY_NAME_TEST = "INJECT"
+const val ROOT_ENTRY_NAME_TEST = "ROOT"
class MacroForTest(private val pageId: String, private val entryId: String) : EntryMacro {
@Composable
@@ -95,12 +98,12 @@ class SettingsEntryTest {
val entryInject = SettingsEntryBuilder.createInject(owner).build()
assertThat(entryInject.id).isEqualTo(
getUniqueEntryId(
- INJECT_ENTRY_NAME,
+ INJECT_ENTRY_NAME_TEST,
owner,
toPage = owner
)
)
- assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME}_mySpp")
+ assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
assertThat(entryInject.fromPage).isNull()
assertThat(entryInject.toPage).isNotNull()
}
@@ -111,7 +114,7 @@ class SettingsEntryTest {
val entryInject = SettingsEntryBuilder.createRoot(owner, "myRootEntry").build()
assertThat(entryInject.id).isEqualTo(
getUniqueEntryId(
- ROOT_ENTRY_NAME,
+ ROOT_ENTRY_NAME_TEST,
owner,
toPage = owner
)
@@ -169,4 +172,25 @@ class SettingsEntryTest {
assertThat(statusData?.isDisabled).isTrue()
assertThat(statusData?.isSwitchOff).isTrue()
}
+
+ @Test
+ fun testSetSliceDataFn() {
+ val owner = SettingsPage.create("mySpp")
+ val entryId = getUniqueEntryId("myEntry", owner)
+ val emptySliceData = EntrySliceData()
+
+ val entryBuilder = SettingsEntryBuilder.create(owner, "myEntry")
+ .setSliceDataFn { uri, _ ->
+ return@setSliceDataFn if (uri.getEntryId() == entryId) emptySliceData else null
+ }
+ val entry = entryBuilder.build()
+ assertThat(entry.id).isEqualTo(entryId)
+ assertThat(entry.hasSliceSupport).isTrue()
+ assertThat(entry.getSliceData(Uri.EMPTY)).isNull()
+ assertThat(
+ entry.getSliceData(
+ Uri.Builder().scheme("content").appendSpaParams(entryId = entryId).build()
+ )
+ ).isEqualTo(emptySliceData)
+ }
}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentTest.kt
new file mode 100644
index 000000000000..3b0e36b91666
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.framework.common
+
+import android.content.Context
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.google.common.truth.Truth
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SpaEnvironmentTest {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val spaEnvironment = SpaEnvironmentForTest(context)
+
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ @Test
+ fun testSpaEnvironmentFactory() {
+ SpaEnvironmentFactory.reset()
+ Truth.assertThat(SpaEnvironmentFactory.isReady()).isFalse()
+ Assert.assertThrows(UnsupportedOperationException::class.java) {
+ SpaEnvironmentFactory.instance
+ }
+
+ SpaEnvironmentFactory.reset(spaEnvironment)
+ Truth.assertThat(SpaEnvironmentFactory.isReady()).isTrue()
+ Truth.assertThat(SpaEnvironmentFactory.instance).isEqualTo(spaEnvironment)
+ }
+
+ @Test
+ fun testSpaEnvironmentFactoryForPreview() {
+ SpaEnvironmentFactory.reset()
+ composeTestRule.setContent {
+ Truth.assertThat(SpaEnvironmentFactory.isReady()).isFalse()
+ SpaEnvironmentFactory.resetForPreview()
+ Truth.assertThat(SpaEnvironmentFactory.isReady()).isTrue()
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
new file mode 100644
index 000000000000..5ea92abefbef
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.framework.theme
+
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import androidx.compose.ui.graphics.Color
+
+@RunWith(AndroidJUnit4::class)
+class SettingsColorsTest {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ @Test
+ fun testDynamicTheme() {
+ // The dynamic color could be different in different device, just check basic restrictions:
+ // 1. text color is different with background color
+ // 2. primary / spinner color is different with its on-item color
+ val ls = dynamicLightColorScheme(context)
+ assertThat(ls.categoryTitle).isNotEqualTo(ls.background)
+ assertThat(ls.secondaryText).isNotEqualTo(ls.background)
+ assertThat(ls.primaryContainer).isNotEqualTo(ls.onPrimaryContainer)
+ assertThat(ls.spinnerHeaderContainer).isNotEqualTo(ls.onSpinnerHeaderContainer)
+ assertThat(ls.spinnerItemContainer).isNotEqualTo(ls.onSpinnerItemContainer)
+
+ val ds = dynamicDarkColorScheme(context)
+ assertThat(ds.categoryTitle).isNotEqualTo(ds.background)
+ assertThat(ds.secondaryText).isNotEqualTo(ds.background)
+ assertThat(ds.primaryContainer).isNotEqualTo(ds.onPrimaryContainer)
+ assertThat(ds.spinnerHeaderContainer).isNotEqualTo(ds.onSpinnerHeaderContainer)
+ assertThat(ds.spinnerItemContainer).isNotEqualTo(ds.onSpinnerItemContainer)
+ }
+
+ @Test
+ fun testStaticTheme() {
+ val ls = lightColorScheme()
+ assertThat(ls.background).isEqualTo(Color(red = 244, green = 239, blue = 244))
+ assertThat(ls.categoryTitle).isEqualTo(Color(red = 103, green = 80, blue = 164))
+ assertThat(ls.surface).isEqualTo(Color(red = 255, green = 251, blue = 254))
+ assertThat(ls.surfaceHeader).isEqualTo(Color(red = 230, green = 225, blue = 229))
+ assertThat(ls.secondaryText).isEqualTo(Color(red = 73, green = 69, blue = 79))
+ assertThat(ls.primaryContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
+ assertThat(ls.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+ assertThat(ls.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
+ assertThat(ls.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+ assertThat(ls.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
+ assertThat(ls.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
+
+ val ds = darkColorScheme()
+ assertThat(ds.background).isEqualTo(Color(red = 28, green = 27, blue = 31))
+ assertThat(ds.categoryTitle).isEqualTo(Color(red = 234, green = 221, blue = 255))
+ assertThat(ds.surface).isEqualTo(Color(red = 49, green = 48, blue = 51))
+ assertThat(ds.surfaceHeader).isEqualTo(Color(red = 72, green = 70, blue = 73))
+ assertThat(ds.secondaryText).isEqualTo(Color(red = 202, green = 196, blue = 208))
+ assertThat(ds.primaryContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
+ assertThat(ds.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+ assertThat(ds.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
+ assertThat(ds.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+ assertThat(ds.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
+ assertThat(ds.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/CollectionsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/CollectionsTest.kt
new file mode 100644
index 000000000000..62f470793a88
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/CollectionsTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.framework.util
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class CollectionsTest {
+ @Test
+ fun testAsyncForEach() = runTest {
+ var sum = 0
+ listOf(1, 2, 3).asyncForEach { sum += it }
+ Truth.assertThat(sum).isEqualTo(6)
+ }
+
+ @Test
+ fun testAsyncFilter() = runTest {
+ val res = listOf(1, 2, 3).asyncFilter { it >= 2 }
+ Truth.assertThat(res).containsExactly(2, 3).inOrder()
+ }
+
+ @Test
+ fun testAsyncMap() = runTest {
+ val res = listOf(1, 2, 3).asyncMap { it + 1 }
+ Truth.assertThat(res).containsExactly(2, 3, 4).inOrder()
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
index 831aded638a2..007d08b81547 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
@@ -41,27 +41,25 @@ class SpaSearchProviderTest {
private val pageOwner = spaEnvironment.createPage("SppForSearch")
@Test
+ fun testQueryColumnSetup() {
+ Truth.assertThat(QueryEnum.SEARCH_STATIC_DATA_QUERY.columnNames)
+ .containsExactlyElementsIn(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.columnNames)
+ Truth.assertThat(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.columnNames)
+ .containsExactlyElementsIn(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.columnNames)
+ Truth.assertThat(QueryEnum.SEARCH_STATIC_ROW_QUERY.columnNames)
+ .containsExactlyElementsIn(QueryEnum.SEARCH_DYNAMIC_ROW_QUERY.columnNames)
+ }
+
+ @Test
fun testQuerySearchStatusData() {
SpaEnvironmentFactory.reset(spaEnvironment)
val immutableStatus = searchProvider.querySearchImmutableStatusData()
- Truth.assertThat(immutableStatus.count).isEqualTo(2)
+ Truth.assertThat(immutableStatus.count).isEqualTo(1)
immutableStatus.moveToFirst()
immutableStatus.checkValue(
QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
ColumnEnum.ENTRY_ID,
- pageOwner.getEntryId("SearchStaticWithNoStatus")
- )
- immutableStatus.checkValue(
- QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
- ColumnEnum.ENTRY_DISABLED,
- false.toString()
- )
-
- immutableStatus.moveToNext()
- immutableStatus.checkValue(
- QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
- ColumnEnum.ENTRY_ID,
pageOwner.getEntryId("SearchDynamicWithImmutableStatus")
)
immutableStatus.checkValue(
@@ -163,6 +161,97 @@ class SpaSearchProviderTest {
listOf("kw1", "kw2").toString()
)
}
+
+ @Test
+ fun testQuerySearchIndexRow() {
+ SpaEnvironmentFactory.reset(spaEnvironment)
+
+ val staticRow = searchProvider.querySearchStaticRow()
+ Truth.assertThat(staticRow.count).isEqualTo(1)
+ staticRow.moveToFirst()
+ staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY,
+ ColumnEnum.ENTRY_ID,
+ pageOwner.getEntryId("SearchStaticWithNoStatus")
+ )
+ staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
+ )
+ staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.SEARCH_KEYWORD, listOf("").toString()
+ )
+ staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY,
+ ColumnEnum.SEARCH_PATH,
+ listOf("SearchStaticWithNoStatus", "SppForSearch").toString()
+ )
+ staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY,
+ ColumnEnum.INTENT_TARGET_PACKAGE,
+ spaEnvironment.appContext.packageName
+ )
+ staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY,
+ ColumnEnum.INTENT_TARGET_CLASS,
+ "com.android.settingslib.spa.tests.testutils.BlankActivity"
+ )
+
+ // Check extras in intent
+ val bundle =
+ staticRow.getExtras(QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.INTENT_EXTRAS)
+ Truth.assertThat(bundle).isNotNull()
+ Truth.assertThat(bundle!!.size()).isEqualTo(3)
+ Truth.assertThat(bundle.getString("spaActivityDestination")).isEqualTo("SppForSearch")
+ Truth.assertThat(bundle.getString("highlightEntry"))
+ .isEqualTo(pageOwner.getEntryId("SearchStaticWithNoStatus"))
+ Truth.assertThat(bundle.getString("sessionSource")).isEqualTo("search")
+
+ Truth.assertThat(
+ staticRow.getString(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY.columnNames.indexOf(
+ ColumnEnum.ENTRY_DISABLED
+ )
+ )
+ ).isNull()
+
+ val dynamicRow = searchProvider.querySearchDynamicRow()
+ Truth.assertThat(dynamicRow.count).isEqualTo(3)
+ dynamicRow.moveToFirst()
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_ID,
+ pageOwner.getEntryId("SearchStaticWithMutableStatus")
+ )
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
+ )
+
+ dynamicRow.moveToNext()
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_ID,
+ pageOwner.getEntryId("SearchDynamicWithMutableStatus")
+ )
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
+ )
+
+
+ dynamicRow.moveToNext()
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_ID,
+ pageOwner.getEntryId("SearchDynamicWithImmutableStatus")
+ )
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.SEARCH_KEYWORD,
+ listOf("kw1", "kw2").toString()
+ )
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
+ )
+ }
}
private fun Cursor.checkValue(query: QueryEnum, column: ColumnEnum, value: String) {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt
index 5611f8ce14db..2140c07090e1 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt
@@ -16,6 +16,9 @@
package com.android.settingslib.spa.widget.preference
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Launch
+import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.semantics.SemanticsProperties.ProgressBarRangeInfo
import androidx.compose.ui.test.SemanticsMatcher
@@ -49,6 +52,7 @@ class ProgressBarPreferenceTest {
ProgressBarWithDataPreference(model = object : ProgressBarPreferenceModel {
override val title = "Title"
override val progress = 0.2f
+ override val icon: ImageVector = Icons.Outlined.Launch
}, data = "Data")
}
composeTestRule.onNodeWithText("Title").assertIsDisplayed()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/ProgressBarTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/ProgressBarTest.kt
new file mode 100644
index 000000000000..072c2cca8b8b
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/ProgressBarTest.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.widget.ui
+
+import androidx.compose.ui.semantics.ProgressBarRangeInfo
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ProgressBarTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ @Test
+ fun testProgressBar() {
+ composeTestRule.setContent {
+ LinearProgressBar(progress = .5f)
+ CircularProgressBar(progress = .2f)
+ }
+
+ fun progressEqualsTo(progress: Float): SemanticsMatcher =
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.ProgressBarRangeInfo,
+ ProgressBarRangeInfo(progress, 0f..1f, 0)
+ )
+ composeTestRule.onNode(progressEqualsTo(0.5f)).assertIsDisplayed()
+ composeTestRule.onNode(progressEqualsTo(0.2f)).assertIsDisplayed()
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/TextTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/TextTest.kt
new file mode 100644
index 000000000000..7e5b4f851250
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/TextTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.spa.widget.ui
+
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.compose.toState
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TextTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ @Test
+ fun testTitle() {
+ composeTestRule.setContent {
+ SettingsTitle(title = "myTitleValue")
+ SettingsTitle(title = "myTitleState".toState())
+ PlaceholderTitle(title = "myTitlePlaceholder")
+ }
+ composeTestRule.onNodeWithText("myTitleState").assertIsDisplayed()
+ composeTestRule.onNodeWithText("myTitleValue").assertIsDisplayed()
+ composeTestRule.onNodeWithText("myTitlePlaceholder").assertIsDisplayed()
+ }
+}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 023433044ac0..fb46dfbfd0ea 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -467,9 +467,8 @@
<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> oor tot vol"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> oor tot vol"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laaiproses is onderbreek"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laaiproses is onderbreek"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laai tot <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laai"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laai tans vinnig"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 29b188c9fed4..fa53f0d54870 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -233,7 +233,7 @@
<string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"የQR ኮድን በመጠቀም መሣሪያን ያጣምሩ"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"የQR ኮድ መቃኛን በመጠቀም አዲስ መሣሪያዎችን ያጣምሩ"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"የማጣመሪያ ኮድን በመጠቀም መሣሪያን ያጣምሩ"</string>
- <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"የስድስት አኃዝ ኮድ በመጠቀም አዲስ መሣሪያዎችን ያጣምሩ"</string>
+ <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"የስድስት አሃዝ ኮድ በመጠቀም አዲስ መሣሪያዎችን ያጣምሩ"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"የተጣመሩ መሣሪያዎች"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"አሁን ላይ ተገናኝቷል"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"የመሣሪያ ዝርዝሮች"</string>
@@ -344,7 +344,7 @@
<string name="wait_for_debugger" msgid="7461199843335409809">"ስህተት ማስወገጃውን ጠብቅ"</string>
<string name="wait_for_debugger_summary" msgid="6846330006113363286">"ስህተቱ የተወገደለት መተግበሪያ ከመፈጸሙ በፊት የስህተት ማስወገጃው እስኪያያዝ ድረስ እየጠበቀው ነው"</string>
<string name="debug_input_category" msgid="7349460906970849771">"ግብዓት"</string>
- <string name="debug_drawing_category" msgid="5066171112313666619">"ስዕል"</string>
+ <string name="debug_drawing_category" msgid="5066171112313666619">"ሥዕል"</string>
<string name="debug_hw_drawing_category" msgid="5830815169336975162">"የተፋጠነ የሃርድዌር አሰጣጥ"</string>
<string name="media_category" msgid="8122076702526144053">"ማህደረመረጃ"</string>
<string name="debug_monitoring_category" msgid="1597387133765424994">"ቁጥጥር"</string>
@@ -467,7 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ኃይል መሙላት ባለበት ቆሟል"</string>
+ <!-- no translation found for power_charging_limited (6732738149313642521) -->
+ <skip />
<!-- no translation found for power_charging_future_paused (6829683663982987290) -->
<skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
@@ -548,10 +549,10 @@
<string name="shared_data_title" msgid="1017034836800864953">"የተጋራ ውሂብ"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"የተጋራ ውሂብን ይመልከቱ እና ያሻሽሉ"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ለዚህ ተጠቃሚ ምንም የተጋራ ውሂብ የለም።"</string>
- <string name="shared_data_query_failure_text" msgid="3489828881998773687">"የተጋራውን ውሂብ በማግኘት ላይ ስሕተት ነበረ። እንደገና ይሞክሩ።"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"የተጋራውን ውሂብ በማግኘት ላይ ስህተት ነበረ። እንደገና ይሞክሩ።"</string>
<string name="blob_id_text" msgid="8680078988996308061">"የተጋራ ውሂብ መታወቂያ፦ <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"በ<xliff:g id="DATE">%s</xliff:g> ላይ የአገልግሎት ጊዜው ያበቃል"</string>
- <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"የተጋራውን ውሂብ በመሰረዝ ላይ ስሕተት ነበረ።"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"የተጋራውን ውሂብ በመሰረዝ ላይ ስህተት ነበረ።"</string>
<string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ለዚህ የተጋራ ውሂብ ምንም የሚያስፈልጉ ኪራዮች የሉም። ሊሰርዙት ይፈልጋሉ?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"ውሂብ የሚጋሩ መተግበሪያዎች"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"በመተግበሪያው ምንም ዝርዝር መረጃ አልተሰጠም።"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 28a3f1872546..88db7be364a6 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - تم إيقاف الشحن مؤقتًا"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - الشحن متوقّف مؤقتًا"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - الشحن حتى <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index fc54e04eb5f6..3f068b4a407b 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - চাৰ্জিং পজ কৰা হৈছে"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - চাৰ্জিং পজ কৰা হৈছে"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>লৈ চাৰ্জিং"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index e2e294f17e1d..8eb8d5b0986a 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -467,9 +467,8 @@
<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">"Tam şarj edilənədək <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - tam şarj edilənədək <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj durdurulub"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj durdurulub"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> olana qədər şarj edilir"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Naməlum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Enerji doldurma"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Sürətlə doldurulur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 479c9ca6d4dd..bbdd8bf32a2e 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -467,9 +467,8 @@
<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> do kraja punjenja"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do kraja punjenja"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Punjenje je zaustavljeno"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Punjenje je pauzirano"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje do <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index b45996cc1644..28c1e864e0f1 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Зарадка прыпынена"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Зарадка прыпынена"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарадка да <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index ecb520866e07..61e441d4e65a 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: Зареждането е на пауза"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – зареждането е на пауза"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарежда се до <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index fda27ed1a80a..a9d32a9349c5 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জিং পজ করা হয়েছে"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জিং পজ করা হয়েছে"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> পর্যন্ত চার্জ হচ্ছে"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজানা"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চার্জ হচ্ছে"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্রুত চার্জ হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index cae96e94518b..b5c917764b94 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -467,9 +467,8 @@
<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> do potpune napunjenosti"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do potpune napunjenosti"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Punjenje je pauzirano"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Punjenje je pauzirano"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Punjenje do <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 51a4a024bd27..8add8c84826f 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -467,9 +467,8 @@
<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> per completar la càrrega"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: la càrrega s\'ha posat en pausa"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g>: la càrrega s\'ha posat en pausa"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g>: s\'està carregant fins al <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a50e52756e02..4dc3c664de5e 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -467,9 +467,8 @@
<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> do úplného nabití"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Nabíjení je pozastaveno"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Nabíjení pozastaveno"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – nabíjení do <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznámé"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíjí se"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rychlé nabíjení"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 95e01304509d..9ab499a7802e 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -467,9 +467,8 @@
<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">"Fuldt opladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – fuldt opladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladningen er sat på pause"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Opladning er sat på pause"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Oplader til <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukendt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Oplader"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Oplader hurtigt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 12fce3718d01..68d61c0efc2e 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -467,9 +467,8 @@
<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">"Voll in <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladevorgang angehalten"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laden pausiert"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Aufladung auf <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index f54d5d2334c7..59ae6389c824 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Η φόρτιση τέθηκε σε παύση"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Φόρτιση σε παύση"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Φόρτιση έως το <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 208dbfac0ad1..3c98c2597722 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -467,9 +467,8 @@
<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> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging paused"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging to <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index aac80ab2997b..833a9e4140de 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -467,7 +467,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging paused"</string>
<string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging to <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 208dbfac0ad1..3c98c2597722 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -467,9 +467,8 @@
<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> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging paused"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging to <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 208dbfac0ad1..3c98c2597722 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -467,9 +467,8 @@
<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> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging paused"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging to <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index bfd7e836a495..b856eb1a2bf0 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -467,7 +467,7 @@
<string name="power_charging" msgid="6727132649743436802">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - ‎‏‎‎‏‏‎<xliff:g id="STATE">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="TIME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ left until full‎‏‎‎‏‎"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - ‎‏‎‎‏‏‎<xliff:g id="TIME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ left until full‎‏‎‎‏‎"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Charging is paused‎‏‎‎‏‎"</string>
+ <string name="power_charging_limited" msgid="6732738149313642521">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Charging paused‎‏‎‎‏‎"</string>
<string name="power_charging_future_paused" msgid="6829683663982987290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Charging to ‎‏‎‎‏‏‎<xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎Unknown‎‏‎‎‏‎"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎Charging‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index c11d6eb002b7..78af70a9456b 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -467,9 +467,8 @@
<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> para completar"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Se pausó la carga"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Se pausó la carga"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Cargando hasta <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 1ef351adb580..ea3047ba8c76 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -467,9 +467,8 @@
<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> hasta la carga completa"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> hasta la carga completa"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga en pausa"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga pausada"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Cargando hasta <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carga rápida"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index e156011fd3bc..78ade679baf7 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -467,9 +467,8 @@
<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">"Täislaadimiseks kulub <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – täislaadimiseks kulub <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine on peatatud"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine peatati"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine tasemeni <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index e5f399c02302..748f991fd71e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -467,9 +467,8 @@
<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> guztiz kargatu arte"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatze-prozesua etenda dago"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatze-prozesua pausatuta dago"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> arte kargatzen"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index ccacfde64616..44e61ef2da31 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - شارژ موقتاً متوقف شده است"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - شارژ موقتاً متوقف شد"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - درحال شارژ تا <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ناشناس"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"در حال شارژ شدن"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"درحال شارژ شدن سریع"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 101dc67eb7a3..2599eb342a2a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -467,9 +467,8 @@
<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> kunnes täynnä"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lataus on keskeytetty"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lataaminen keskeytetty"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tavoite: <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index ff58a518b833..314e8d1f951c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -467,9 +467,8 @@
<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> jusqu\'à la recharge complète"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la recharge complète)"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - La recharge est interrompue"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Recharge interrompue"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - En charge jusqu\'à <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index f9725f65f961..5cab1dea9c29 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -467,9 +467,8 @@
<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">"Chargée à 100 %% dans <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – La recharge est en pause"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Recharge interrompue"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Recharge jusqu\'à <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 3ceb99ce9d92..52bdaf6156a2 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -467,9 +467,8 @@
<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> para completar a carga"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> para completar a carga)"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: a carga está en pausa"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g>: Carga en pausa"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g>: Cargando ata o <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 1821546d4ea9..5a875a720827 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ થોભાવવામાં આવ્યું છે"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ થોભાવેલું છે"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> સુધી ચાર્જિંગ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 4b899bb83142..0a38d16621fb 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग को रोका गया है"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग रोकी गई है"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> तक चार्ज किया जा रहा है"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
@@ -602,7 +601,7 @@
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"मिटाएं"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"सेव करें"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"मेहमान मोड से बाहर निकलें"</string>
- <string name="guest_reset_button" msgid="2515069346223503479">"मेहमान मोड के सेशन को रीसेट करें?"</string>
+ <string name="guest_reset_button" msgid="2515069346223503479">"मेहमान मोड के सेशन को रीसेट करें"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"मेहमान मोड से बाहर निकलें"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"बाहर निकलने पर, सारी गतिविधि मिट जाएगी"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"बाहर निकलने पर, गतिविधि को मिटाया या सेव किया जा सकता है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 46c8b9030ad3..03eba0f9629b 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -467,9 +467,8 @@
<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> do napunjenosti"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je pauzirano"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje pauzirano"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje do <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index d74490f17d92..04a3ac6411ba 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -467,9 +467,8 @@
<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> a teljes töltöttségig"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes töltöttségig"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – A töltés szünetel"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Töltés szüneteltetve"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Töltés eddig: <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Gyorstöltés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index c26f94f0cc59..13f969cd08ee 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը դադարեցված է"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը դադարեցվել է"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորում մինչև <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 203485fc0ee7..650d50bbe9ba 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -467,9 +467,8 @@
<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> lagi sampai penuh"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sampai penuh"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dijeda"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dijeda"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Mengisi daya sampai <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 918587730172..da576f5cf362 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -467,9 +467,8 @@
<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> fram að fullri hleðslu"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> fram að fullri hleðslu"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Hlé var gert á hleðslu"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Hlé gert á hleðslu"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - hleður upp að <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 0cd9e1e4b2f9..70425065c407 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -467,9 +467,8 @@
<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> alla ricarica completa"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla ricarica completa"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica in pausa"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica in pausa"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica fino a <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Sconosciuta"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"In carica"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ricarica veloce"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 629310543efb..143c99de9102 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה הושהתה"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה מושהית"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – טעינה עד מצב של <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"לא ידוע"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"בטעינה"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"הסוללה נטענת מהר"</string>
@@ -514,7 +513,7 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"לא רשום"</string>
<string name="status_unavailable" msgid="5279036186589861608">"לא זמין"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"‏כתובת ה-MAC אקראית"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{אין מכשירים מחוברים}=1{מכשיר אחד מחובר}two{# מכשירים מחוברים}many{# מכשירים מחוברים}other{# מכשירים מחוברים}}"</string>
+ <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{אין מכשירים מחוברים}=1{מכשיר אחד מחובר}one{# מכשירים מחוברים}two{# מכשירים מחוברים}other{# מכשירים מחוברים}}"</string>
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"יותר זמן."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"פחות זמן."</string>
<string name="cancel" msgid="5665114069455378395">"ביטול"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9a9d6ea2c15a..11a525865754 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電は一時停止中"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電を一時停止しています"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> まで充電"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 2fa2d8095d36..d6c0f38c7c00 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - დატენვა ᲨეᲩერებულია"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - დატენვა დაპაუზებულია"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – დატენვა შემდეგ ნიშნულამდე: <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"უცნობი"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"იტენება"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"სწრაფად იტენება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index a33200401d68..96f2595003c7 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядтау кідіртілді."</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зарядтау кідіртілді"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> деңгейіне дейін зарядталады"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядталуда"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 2d78295ecceb..db4afdff3d86 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ការសាកថ្មត្រូវបានផ្អាក"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - បានផ្អាក​ការសាកថ្ម"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - កំពុង​សាកថ្ម​ឱ្យដល់កម្រិត <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"មិន​ស្គាល់"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងសាក​ថ្ម"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 5db4b1622c34..74c2c74371e2 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ವಿರಾಮಗೊಂಡಿದೆ"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> ವರೆಗೆ ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 30ab26c7450e..7a8ce1a1bc3d 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 일시중지됨"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 일시중지됨"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>까지 충전"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index baacfd7d27d3..534c94ffc49e 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо тындырылды"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо тындырылды"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> чейин кубаттоо"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгисиз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Кубатталууда"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ыкчам кубатталууда"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 36755f7343b5..f37a4ea0ec18 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ການສາກໄຟຖືກຢຸດໄວ້ຊົ່ວຄາວ"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ຢຸດການສາກໄວ້ຊົ່ວຄາວແລ້ວ"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - ກຳລັງສາກຈົນເຖິງ <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ບໍ່ຮູ້ຈັກ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ກຳລັງສາກໄຟ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ກຳລັງສາກໄຟດ່ວນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 50652ea56924..cdfa11570f6b 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -467,9 +467,8 @@
<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">"Liko <xliff:g id="TIME">%1$s</xliff:g>, kol bus visiškai įkrauta"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko <xliff:g id="TIME">%2$s</xliff:g>, kol bus visiškai įkrauta"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkrovimas pristabdytas"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkrovimas pristabdytas"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkraunama iki <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nežinomas"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kraunasi..."</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Greitai įkraunama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index c199feab7974..a5ecfff41d03 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -467,9 +467,8 @@
<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> līdz pilnai uzlādei"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> — uzlāde ir pārtraukta"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Uzlāde ir apturēta"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g>. Tiks uzlādēts līdz <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nezināms"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Uzlāde"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Notiek ātrā uzlāde"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 957f68bcfbae..a41d953f6b11 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е паузирано"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е паузирано"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Се полни на <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Се полни"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо полнење"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1cc92cad7786..83b87f86a9fe 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ചാർജിംഗ് താൽക്കാലികമായി നിർത്തി"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ചാർജ് ചെയ്യൽ താൽക്കാലികമായി നിർത്തി"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> വരെ ചാർജ് ചെയ്യുന്നു"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"അജ്ഞാതം"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ചാർജ് ചെയ്യുന്നു"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"അതിവേഗ ചാർജിംഗ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index a107c70caf37..b77d8fb18804 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэхийг түр зогсоосон"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэлтийг түр зогсоосон"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> руу цэнэглэж байна"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index d5c83a8c9a91..9d91684f9e91 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज करणे थांबवले आहे"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज करणे थांबवले"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> वर चार्ज करत आहे"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index ae8be8ef0b0f..d30221404afd 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -467,9 +467,8 @@
<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> lagi sebelum penuh"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sebelum penuh"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan dijeda"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan dijeda"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Mengecas kepada <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index f16cdcab32f7..1e26b08577a9 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းမှု ခဏရပ်ထားသည်"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> အထိ အားသွင်းရန်"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"မသိ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"အားသွင်းနေပါသည်"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"အမြန် အားသွင်းနေသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index f7a10a6b26cc..be5259708fca 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -467,9 +467,8 @@
<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">"Fulladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Fulladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ladingen er satt på pause"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ladingen er satt på pause"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – lader til <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index a966f1560b06..4d2eb2e70f1e 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज गर्ने प्रक्रिया रोकिएको छ"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज गर्ने प्रक्रिया पज गरिएको छ"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> सम्म चार्ज हुने छ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै छ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index c5406ee74d7e..898da111618e 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -467,9 +467,8 @@
<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">"Vol over <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - vol over <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladen is onderbroken"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladen onderbroken"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladen tot <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Opladen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Snel opladen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 37cc25e58bd1..6b6752f637cc 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂକୁ ବିରତ କରାଯାଇଛି"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂ ବିରତ କରାଯାଇଛି"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ଅଜ୍ଞାତ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 767cbc5f0022..896b5eca4edc 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਦੀ ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> ਤੱਕ ਚਾਰਜ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 48bc82e8ee4c..263e0d7b81a5 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -467,9 +467,8 @@
<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> do pełnego naładowania"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – ładowanie zostało wstrzymane"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – wstrzymano ładowanie"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ładuję do <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 68a1c49c486c..e1070644431b 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -467,9 +467,8 @@
<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> até a conclusão"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: o carregamento está pausado"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g>: carregamento pausado"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g>: carregando até <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 87bab5072057..165ecc483733 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -467,9 +467,8 @@
<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> até à carga máxima"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até à carga máxima"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – O carregamento está pausado"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Carregamento em pausa"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – A carregar até <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"A carregar"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregamento rápido"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 68a1c49c486c..e1070644431b 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -467,9 +467,8 @@
<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> até a conclusão"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: o carregamento está pausado"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g>: carregamento pausado"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g>: carregando até <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index f81ef4c89e2d..44ec043e9f5c 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -467,9 +467,8 @@
<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> până la finalizare"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> până la finalizare"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcarea este întreruptă"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcarea s-a întrerupt"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Se încarcă până la <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 4dcee136b870..102cf1b98521 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: зарядка приостановлена"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядка приостановлена"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряжается до <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Идет зарядка"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Быстрая зарядка"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 17c59eaad41d..a8963af20e94 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය විරාම කර ඇත"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය විරාම කළා"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> වෙත ආරෝපණය"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index d9ce6cf77e68..d7bdd8999a49 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -467,9 +467,8 @@
<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> do úplného nabitia"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Nabíjanie je pozastavené"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – nabíjanie bolo pozastavené"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – nabíja sa na úroveň <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznáme"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíja sa"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rýchle nabíjanie"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 8f9b059c3b9a..6cb5b3c9632d 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -467,9 +467,8 @@
<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">"Še <xliff:g id="TIME">%1$s</xliff:g> do napolnjenosti"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – še <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Polnjenje je začasno zaustavljeno"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – polnjenje je začasno zaustavljeno"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – polnjenje do <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index d467eeab1912..54a8361bdd47 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -467,9 +467,8 @@
<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> derisa të mbushet"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të mbushet"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi është vendosur në pauzë"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi në pauzë"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Po karikohet deri në <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Karikim i shpejtë"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 9cc43d98c486..d61938b5ce64 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Пуњење је заустављено"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Пуњење је паузирано"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – пуњење до <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 89deafa2cd67..3ba4e9bc7acb 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -467,9 +467,8 @@
<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> kvar tills fulladdat"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kvar tills fulladdat"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laddningen har pausats"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laddningen har pausats"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laddar till <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 1fa5eddd6e86..c1676971879a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -467,9 +467,8 @@
<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">"Zimesalia <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> zimesalia ijae chaji"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Imesitisha kuchaji"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Imesitisha kuchaji"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Itachaji hadi <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 1b7b643ab081..57661ba15da6 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜ் ஏறுவது இடைநிறுத்தப்பட்டுள்ளது"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜிங் இடைநிறுத்தப்பட்டது"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> வரை சார்ஜ் செய்யப்படும்"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"அறியப்படாத"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"சார்ஜ் ஆகிறது"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"வேகமாக சார்ஜாகிறது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 27e9dbd09978..365a8f2115d1 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జింగ్ పాజ్ చేయబడింది"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జింగ్ పాజ్ చేయబడింది"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> ఛార్జింగ్"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 6b9c077a4f1b..cea4dd20e718 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - การชาร์จหยุดชั่วคราว"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - หยุดชาร์จชั่วคราว"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - กำลังชาร์จจนถึง <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index fddc1d0cf8fb..e4503a022c25 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -467,9 +467,8 @@
<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> na lang bago mapuno"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> na lang bago mapuno"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Naka-pause ang pag-charge"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Na-pause ang pag-charge"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - China-charge hanggang <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Hindi Kilala"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nagcha-charge"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mabilis na charge"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 31dcedb8eeaf..eada4809ff23 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -467,9 +467,8 @@
<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">"Tamamen şarj olmasına <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: Şarj işlemi duraklatıldı"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj işlemi duraklatıldı"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> seviyesine kadar şarj ediliyor"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 2fdc2273d2ad..8ab8db7eb545 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Заряджання призупинено"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряджання призупинено"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Заряджання до <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 82dbdb3c1597..ebc6edca76fa 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - چارجنگ موقوف ہے"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - چارجنگ موقوف کی گئی"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> چارج کیا جائے گا"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index ab997b6c649c..19601ddcd4f9 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -467,9 +467,8 @@
<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">"Toʻlishiga <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Toʻlishiga <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quvvatlash pauza qilindi"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Quvvatlash pauzada"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g>, <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> gacha quvvat oladi"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 44c820a5a548..f9004807296f 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -467,9 +467,8 @@
<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> nữa là pin đầy"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> nữa là pin đầy"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đã tạm dừng sạc"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đã tạm dừng sạc"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> – Sạc đến <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Không xác định"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Đang sạc"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Đang sạc nhanh"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index eae1c391415d..6909f22639c8 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -141,7 +141,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"取消"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"配对之后,所配对的设备将可以在建立连接后访问您的通讯录和通话记录。"</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"无法与“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”进行配对。"</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"PIN 码或密钥不正确,因此无法与“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”配对。"</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"PIN 码或通行密钥不正确,因此无法与“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”配对。"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"无法与“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”进行通信。"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> 已拒绝配对。"</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"计算机"</string>
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充电已暂停"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暂停充电"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在充到 <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"正在充电"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充电"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 4371bb30e865..2d59d2d3803e 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暫停充電"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暫停充電"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在充電至 <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index d76a4a45288f..40b42fcccb9b 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -467,9 +467,8 @@
<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_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="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暫停充電"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暫停充電"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在充電至 <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 4dc7651ffc75..a73f067183d0 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -467,9 +467,8 @@
<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> okusele kuze kugcwale"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> okusele kuze kugcwale"</string>
- <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ukushaja kumisiwe okwesikhashana"</string>
- <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
- <skip />
+ <string name="power_charging_limited" msgid="6732738149313642521">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ukushaja kumiswe isikhashana"</string>
+ <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ishaja ku-<xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Akwaziwa"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Iyashaja"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ishaja ngokushesha"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
index 1745379c3034..7516d2e6ab1b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
@@ -28,6 +28,7 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.ParentalControlsUtilsInternal;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.text.TextUtils;
/**
@@ -82,6 +83,12 @@ public final class ActionDisabledByAdminControllerFactory {
private static boolean isFinancedDevice(Context context) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+ // TODO(b/259908270): remove
+ if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG,
+ DevicePolicyManager.ADD_ISFINANCED_FEVICE_DEFAULT)) {
+ return dpm.isFinancedDevice();
+ }
return dpm.isDeviceManaged() && dpm.getDeviceOwnerType(
dpm.getDeviceOwnerComponentOnAnyUser()) == DEVICE_OWNER_TYPE_FINANCED;
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 68455c8347ff..47794b8427db 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -23,6 +23,7 @@
>
<!-- Standard permissions granted to the shell. -->
+ <uses-permission android:name="android.permission.MANAGE_HEALTH_DATA" />
<uses-permission android:name="android.permission.LAUNCH_DEVICE_MANAGER_SETUP" />
<uses-permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.SEND_SMS" />
@@ -321,7 +322,9 @@
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_COMPUTER" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION" />
+ <uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_WATCH" />
+ <uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_GLASSES" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_SELF_MANAGED" />
<uses-permission android:name="android.permission.MANAGE_APPOPS" />
@@ -780,80 +783,6 @@
<!-- Permission required for CTS test - CtsHardwareTestCases -->
<uses-permission android:name="android.permission.REMAP_MODIFIER_KEYS" />
- <!-- Permissions required for CTS test - CtsAppFgsTestCases -->
- <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />
- <uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" />
- <uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" />
- <uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" />
- <uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE" />
- <uses-permission android:name="android.permission.health.READ_BODY_FAT" />
- <uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" />
- <uses-permission android:name="android.permission.health.READ_BODY_WATER_MASS" />
- <uses-permission android:name="android.permission.health.READ_BONE_MASS" />
- <uses-permission android:name="android.permission.health.READ_CERVICAL_MUCUS" />
- <uses-permission android:name="android.permission.health.READ_DISTANCE" />
- <uses-permission android:name="android.permission.health.READ_ELEVATION_GAINED" />
- <uses-permission android:name="android.permission.health.READ_EXERCISE" />
- <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
- <uses-permission android:name="android.permission.health.READ_HEART_RATE" />
- <uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" />
- <uses-permission android:name="android.permission.health.READ_HEIGHT" />
- <uses-permission android:name="android.permission.health.READ_HIP_CIRCUMFERENCE" />
- <uses-permission android:name="android.permission.health.READ_HYDRATION" />
- <uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS" />
- <uses-permission android:name="android.permission.health.READ_MENSTRUATION" />
- <uses-permission android:name="android.permission.health.READ_NUTRITION" />
- <uses-permission android:name="android.permission.health.READ_OVULATION_TEST" />
- <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" />
- <uses-permission android:name="android.permission.health.READ_POWER" />
- <uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE" />
- <uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE" />
- <uses-permission android:name="android.permission.health.READ_SEXUAL_ACTIVITY" />
- <uses-permission android:name="android.permission.health.READ_SLEEP" />
- <uses-permission android:name="android.permission.health.READ_SPEED" />
- <uses-permission android:name="android.permission.health.READ_STEPS" />
- <uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" />
- <uses-permission android:name="android.permission.health.READ_VO2_MAX" />
- <uses-permission android:name="android.permission.health.READ_WAIST_CIRCUMFERENCE" />
- <uses-permission android:name="android.permission.health.READ_WEIGHT" />
- <uses-permission android:name="android.permission.health.READ_WHEELCHAIR_PUSHES" />
- <uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED" />
- <uses-permission android:name="android.permission.health.WRITE_BASAL_BODY_TEMPERATURE" />
- <uses-permission android:name="android.permission.health.WRITE_BASAL_METABOLIC_RATE" />
- <uses-permission android:name="android.permission.health.WRITE_BLOOD_GLUCOSE" />
- <uses-permission android:name="android.permission.health.WRITE_BLOOD_PRESSURE" />
- <uses-permission android:name="android.permission.health.WRITE_BODY_FAT" />
- <uses-permission android:name="android.permission.health.WRITE_BODY_TEMPERATURE" />
- <uses-permission android:name="android.permission.health.WRITE_BODY_WATER_MASS" />
- <uses-permission android:name="android.permission.health.WRITE_BONE_MASS" />
- <uses-permission android:name="android.permission.health.WRITE_CERVICAL_MUCUS" />
- <uses-permission android:name="android.permission.health.WRITE_DISTANCE" />
- <uses-permission android:name="android.permission.health.WRITE_ELEVATION_GAINED" />
- <uses-permission android:name="android.permission.health.WRITE_EXERCISE" />
- <uses-permission android:name="android.permission.health.WRITE_FLOORS_CLIMBED" />
- <uses-permission android:name="android.permission.health.WRITE_HEART_RATE" />
- <uses-permission android:name="android.permission.health.WRITE_HEART_RATE_VARIABILITY" />
- <uses-permission android:name="android.permission.health.WRITE_HEIGHT" />
- <uses-permission android:name="android.permission.health.WRITE_HIP_CIRCUMFERENCE" />
- <uses-permission android:name="android.permission.health.WRITE_HYDRATION" />
- <uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS" />
- <uses-permission android:name="android.permission.health.WRITE_MENSTRUATION" />
- <uses-permission android:name="android.permission.health.WRITE_NUTRITION" />
- <uses-permission android:name="android.permission.health.WRITE_OVULATION_TEST" />
- <uses-permission android:name="android.permission.health.WRITE_OXYGEN_SATURATION" />
- <uses-permission android:name="android.permission.health.WRITE_POWER" />
- <uses-permission android:name="android.permission.health.WRITE_RESPIRATORY_RATE" />
- <uses-permission android:name="android.permission.health.WRITE_RESTING_HEART_RATE" />
- <uses-permission android:name="android.permission.health.WRITE_SEXUAL_ACTIVITY" />
- <uses-permission android:name="android.permission.health.WRITE_SLEEP" />
- <uses-permission android:name="android.permission.health.WRITE_SPEED" />
- <uses-permission android:name="android.permission.health.WRITE_STEPS" />
- <uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED" />
- <uses-permission android:name="android.permission.health.WRITE_VO2_MAX" />
- <uses-permission android:name="android.permission.health.WRITE_WAIST_CIRCUMFERENCE" />
- <uses-permission android:name="android.permission.health.WRITE_WEIGHT" />
- <uses-permission android:name="android.permission.health.WRITE_WHEELCHAIR_PUSHES" />
-
<!-- Permission required for CTS test - ApplicationExemptionsTests -->
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 68679c794c35..6f7d20a950d5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -455,8 +455,7 @@ public class BugreportProgressService extends Service {
intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_NONCE, nonce);
intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
- context.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
- android.Manifest.permission.DUMP);
+ context.sendBroadcast(intent, android.Manifest.permission.DUMP);
}
/**
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a8216e89b0fd..4538179e73ab 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -23,11 +23,6 @@
xmlns:tools="http://schemas.android.com/tools"
coreApp="true">
- <!-- Using OpenGL ES 2.0 -->
- <uses-feature
- android:glEsVersion="0x00020000"
- android:required="true" />
-
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Used to read wallpaper -->
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index aaee42fe05f0..f92625bd9a73 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -33,6 +33,18 @@
]
},
{
+ // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
+ "name": "SystemUIGoogleBiometricsScreenshotTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
// Permission indicators
"name": "CtsPermission4TestCases",
"options": [
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
index 93e78acc63fd..8cd8bf6ca1db 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
@@ -21,9 +21,20 @@ import androidx.annotation.VisibleForTesting
/** Controller that handles playing [RippleAnimation]. */
class MultiRippleController(private val multipleRippleView: MultiRippleView) {
+ private val ripplesFinishedListeners = ArrayList<RipplesFinishedListener>()
+
companion object {
/** Max number of ripple animations at a time. */
@VisibleForTesting const val MAX_RIPPLE_NUMBER = 10
+
+ interface RipplesFinishedListener {
+ /** Triggered when all the ripples finish running. */
+ fun onRipplesFinish()
+ }
+ }
+
+ fun addRipplesFinishedListener(listener: RipplesFinishedListener) {
+ ripplesFinishedListeners.add(listener)
}
/** Updates all the ripple colors during the animation. */
@@ -38,8 +49,13 @@ class MultiRippleController(private val multipleRippleView: MultiRippleView) {
multipleRippleView.ripples.add(rippleAnimation)
- // Remove ripple once the animation is done
- rippleAnimation.play { multipleRippleView.ripples.remove(rippleAnimation) }
+ rippleAnimation.play {
+ // Remove ripple once the animation is done
+ multipleRippleView.ripples.remove(rippleAnimation)
+ if (multipleRippleView.ripples.isEmpty()) {
+ ripplesFinishedListeners.forEach { listener -> listener.onRipplesFinish() }
+ }
+ }
// Trigger drawing
multipleRippleView.invalidate()
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
index b8dc223af56c..550d2c6d8732 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
@@ -33,21 +33,11 @@ class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, a
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
val ripples = ArrayList<RippleAnimation>()
- private val listeners = ArrayList<RipplesFinishedListener>()
private val ripplePaint = Paint()
private var isWarningLogged = false
companion object {
private const val TAG = "MultiRippleView"
-
- interface RipplesFinishedListener {
- /** Triggered when all the ripples finish running. */
- fun onRipplesFinish()
- }
- }
-
- fun addRipplesFinishedListener(listener: RipplesFinishedListener) {
- listeners.add(listener)
}
override fun onDraw(canvas: Canvas?) {
@@ -76,8 +66,6 @@ class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, a
if (shouldInvalidate) {
invalidate()
- } else { // Nothing is playing.
- listeners.forEach { listener -> listener.onRipplesFinish() }
}
}
}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt
index 79e3d3d475a8..00532f4e46b8 100644
--- a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt
@@ -18,12 +18,17 @@ package com.android.systemui.compose.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Typography
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
+import com.android.systemui.compose.theme.typography.TypeScaleTokens
+import com.android.systemui.compose.theme.typography.TypefaceNames
+import com.android.systemui.compose.theme.typography.TypefaceTokens
+import com.android.systemui.compose.theme.typography.TypographyTokens
+import com.android.systemui.compose.theme.typography.systemUITypography
/** The Material 3 theme that should wrap all SystemUI Composables. */
@Composable
@@ -33,7 +38,7 @@ fun SystemUITheme(
) {
val context = LocalContext.current
- // TODO(b/230605885): Define our typography and color scheme.
+ // TODO(b/230605885): Define our color scheme.
val colorScheme =
if (isDarkTheme) {
dynamicDarkColorScheme(context)
@@ -41,7 +46,11 @@ fun SystemUITheme(
dynamicLightColorScheme(context)
}
val androidColorScheme = AndroidColorScheme(context)
- val typography = Typography()
+ val typefaceNames = remember(context) { TypefaceNames.get(context) }
+ val typography =
+ remember(typefaceNames) {
+ systemUITypography(TypographyTokens(TypeScaleTokens(TypefaceTokens(typefaceNames))))
+ }
MaterialTheme(colorScheme, typography = typography) {
CompositionLocalProvider(
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/SystemUITypography.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/SystemUITypography.kt
new file mode 100644
index 000000000000..365f4bb69897
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/SystemUITypography.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.compose.theme.typography
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+
+/**
+ * The SystemUI typography.
+ *
+ * Do not use directly and call [MaterialTheme.typography] instead to access the different text
+ * styles.
+ */
+internal fun systemUITypography(typographyTokens: TypographyTokens): Typography {
+ return Typography(
+ displayLarge = typographyTokens.displayLarge,
+ displayMedium = typographyTokens.displayMedium,
+ displaySmall = typographyTokens.displaySmall,
+ headlineLarge = typographyTokens.headlineLarge,
+ headlineMedium = typographyTokens.headlineMedium,
+ headlineSmall = typographyTokens.headlineSmall,
+ titleLarge = typographyTokens.titleLarge,
+ titleMedium = typographyTokens.titleMedium,
+ titleSmall = typographyTokens.titleSmall,
+ bodyLarge = typographyTokens.bodyLarge,
+ bodyMedium = typographyTokens.bodyMedium,
+ bodySmall = typographyTokens.bodySmall,
+ labelLarge = typographyTokens.labelLarge,
+ labelMedium = typographyTokens.labelMedium,
+ labelSmall = typographyTokens.labelSmall,
+ )
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypeScaleTokens.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypeScaleTokens.kt
new file mode 100644
index 000000000000..537ba0b7a834
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypeScaleTokens.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.compose.theme.typography
+
+import androidx.compose.ui.unit.sp
+
+internal class TypeScaleTokens(typefaceTokens: TypefaceTokens) {
+ val bodyLargeFont = typefaceTokens.plain
+ val bodyLargeLineHeight = 24.0.sp
+ val bodyLargeSize = 16.sp
+ val bodyLargeTracking = 0.0.sp
+ val bodyLargeWeight = TypefaceTokens.WeightRegular
+ val bodyMediumFont = typefaceTokens.plain
+ val bodyMediumLineHeight = 20.0.sp
+ val bodyMediumSize = 14.sp
+ val bodyMediumTracking = 0.0.sp
+ val bodyMediumWeight = TypefaceTokens.WeightRegular
+ val bodySmallFont = typefaceTokens.plain
+ val bodySmallLineHeight = 16.0.sp
+ val bodySmallSize = 12.sp
+ val bodySmallTracking = 0.1.sp
+ val bodySmallWeight = TypefaceTokens.WeightRegular
+ val displayLargeFont = typefaceTokens.brand
+ val displayLargeLineHeight = 64.0.sp
+ val displayLargeSize = 57.sp
+ val displayLargeTracking = 0.0.sp
+ val displayLargeWeight = TypefaceTokens.WeightRegular
+ val displayMediumFont = typefaceTokens.brand
+ val displayMediumLineHeight = 52.0.sp
+ val displayMediumSize = 45.sp
+ val displayMediumTracking = 0.0.sp
+ val displayMediumWeight = TypefaceTokens.WeightRegular
+ val displaySmallFont = typefaceTokens.brand
+ val displaySmallLineHeight = 44.0.sp
+ val displaySmallSize = 36.sp
+ val displaySmallTracking = 0.0.sp
+ val displaySmallWeight = TypefaceTokens.WeightRegular
+ val headlineLargeFont = typefaceTokens.brand
+ val headlineLargeLineHeight = 40.0.sp
+ val headlineLargeSize = 32.sp
+ val headlineLargeTracking = 0.0.sp
+ val headlineLargeWeight = TypefaceTokens.WeightRegular
+ val headlineMediumFont = typefaceTokens.brand
+ val headlineMediumLineHeight = 36.0.sp
+ val headlineMediumSize = 28.sp
+ val headlineMediumTracking = 0.0.sp
+ val headlineMediumWeight = TypefaceTokens.WeightRegular
+ val headlineSmallFont = typefaceTokens.brand
+ val headlineSmallLineHeight = 32.0.sp
+ val headlineSmallSize = 24.sp
+ val headlineSmallTracking = 0.0.sp
+ val headlineSmallWeight = TypefaceTokens.WeightRegular
+ val labelLargeFont = typefaceTokens.plain
+ val labelLargeLineHeight = 20.0.sp
+ val labelLargeSize = 14.sp
+ val labelLargeTracking = 0.0.sp
+ val labelLargeWeight = TypefaceTokens.WeightMedium
+ val labelMediumFont = typefaceTokens.plain
+ val labelMediumLineHeight = 16.0.sp
+ val labelMediumSize = 12.sp
+ val labelMediumTracking = 0.1.sp
+ val labelMediumWeight = TypefaceTokens.WeightMedium
+ val labelSmallFont = typefaceTokens.plain
+ val labelSmallLineHeight = 16.0.sp
+ val labelSmallSize = 11.sp
+ val labelSmallTracking = 0.1.sp
+ val labelSmallWeight = TypefaceTokens.WeightMedium
+ val titleLargeFont = typefaceTokens.brand
+ val titleLargeLineHeight = 28.0.sp
+ val titleLargeSize = 22.sp
+ val titleLargeTracking = 0.0.sp
+ val titleLargeWeight = TypefaceTokens.WeightRegular
+ val titleMediumFont = typefaceTokens.plain
+ val titleMediumLineHeight = 24.0.sp
+ val titleMediumSize = 16.sp
+ val titleMediumTracking = 0.0.sp
+ val titleMediumWeight = TypefaceTokens.WeightMedium
+ val titleSmallFont = typefaceTokens.plain
+ val titleSmallLineHeight = 20.0.sp
+ val titleSmallSize = 14.sp
+ val titleSmallTracking = 0.0.sp
+ val titleSmallWeight = TypefaceTokens.WeightMedium
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypefaceTokens.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypefaceTokens.kt
new file mode 100644
index 000000000000..f3d554fc9363
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypefaceTokens.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalTextApi::class)
+
+package com.android.systemui.compose.theme.typography
+
+import android.content.Context
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.font.DeviceFontFamilyName
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+
+internal class TypefaceTokens(typefaceNames: TypefaceNames) {
+ companion object {
+ val WeightMedium = FontWeight.Medium
+ val WeightRegular = FontWeight.Normal
+ }
+
+ private val brandFont = DeviceFontFamilyName(typefaceNames.brand)
+ private val plainFont = DeviceFontFamilyName(typefaceNames.plain)
+
+ val brand =
+ FontFamily(
+ Font(brandFont, weight = WeightMedium),
+ Font(brandFont, weight = WeightRegular),
+ )
+ val plain =
+ FontFamily(
+ Font(plainFont, weight = WeightMedium),
+ Font(plainFont, weight = WeightRegular),
+ )
+}
+
+internal data class TypefaceNames
+private constructor(
+ val brand: String,
+ val plain: String,
+) {
+ private enum class Config(val configName: String, val default: String) {
+ Brand("config_headlineFontFamily", "sans-serif"),
+ Plain("config_bodyFontFamily", "sans-serif"),
+ }
+
+ companion object {
+ fun get(context: Context): TypefaceNames {
+ return TypefaceNames(
+ brand = getTypefaceName(context, Config.Brand),
+ plain = getTypefaceName(context, Config.Plain),
+ )
+ }
+
+ private fun getTypefaceName(context: Context, config: Config): String {
+ return context
+ .getString(context.resources.getIdentifier(config.configName, "string", "android"))
+ .takeIf { it.isNotEmpty() }
+ ?: config.default
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypographyTokens.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypographyTokens.kt
new file mode 100644
index 000000000000..55f3d1fef05a
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/typography/TypographyTokens.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.compose.theme.typography
+
+import androidx.compose.ui.text.TextStyle
+
+internal class TypographyTokens(typeScaleTokens: TypeScaleTokens) {
+ val bodyLarge =
+ TextStyle(
+ fontFamily = typeScaleTokens.bodyLargeFont,
+ fontWeight = typeScaleTokens.bodyLargeWeight,
+ fontSize = typeScaleTokens.bodyLargeSize,
+ lineHeight = typeScaleTokens.bodyLargeLineHeight,
+ letterSpacing = typeScaleTokens.bodyLargeTracking,
+ )
+ val bodyMedium =
+ TextStyle(
+ fontFamily = typeScaleTokens.bodyMediumFont,
+ fontWeight = typeScaleTokens.bodyMediumWeight,
+ fontSize = typeScaleTokens.bodyMediumSize,
+ lineHeight = typeScaleTokens.bodyMediumLineHeight,
+ letterSpacing = typeScaleTokens.bodyMediumTracking,
+ )
+ val bodySmall =
+ TextStyle(
+ fontFamily = typeScaleTokens.bodySmallFont,
+ fontWeight = typeScaleTokens.bodySmallWeight,
+ fontSize = typeScaleTokens.bodySmallSize,
+ lineHeight = typeScaleTokens.bodySmallLineHeight,
+ letterSpacing = typeScaleTokens.bodySmallTracking,
+ )
+ val displayLarge =
+ TextStyle(
+ fontFamily = typeScaleTokens.displayLargeFont,
+ fontWeight = typeScaleTokens.displayLargeWeight,
+ fontSize = typeScaleTokens.displayLargeSize,
+ lineHeight = typeScaleTokens.displayLargeLineHeight,
+ letterSpacing = typeScaleTokens.displayLargeTracking,
+ )
+ val displayMedium =
+ TextStyle(
+ fontFamily = typeScaleTokens.displayMediumFont,
+ fontWeight = typeScaleTokens.displayMediumWeight,
+ fontSize = typeScaleTokens.displayMediumSize,
+ lineHeight = typeScaleTokens.displayMediumLineHeight,
+ letterSpacing = typeScaleTokens.displayMediumTracking,
+ )
+ val displaySmall =
+ TextStyle(
+ fontFamily = typeScaleTokens.displaySmallFont,
+ fontWeight = typeScaleTokens.displaySmallWeight,
+ fontSize = typeScaleTokens.displaySmallSize,
+ lineHeight = typeScaleTokens.displaySmallLineHeight,
+ letterSpacing = typeScaleTokens.displaySmallTracking,
+ )
+ val headlineLarge =
+ TextStyle(
+ fontFamily = typeScaleTokens.headlineLargeFont,
+ fontWeight = typeScaleTokens.headlineLargeWeight,
+ fontSize = typeScaleTokens.headlineLargeSize,
+ lineHeight = typeScaleTokens.headlineLargeLineHeight,
+ letterSpacing = typeScaleTokens.headlineLargeTracking,
+ )
+ val headlineMedium =
+ TextStyle(
+ fontFamily = typeScaleTokens.headlineMediumFont,
+ fontWeight = typeScaleTokens.headlineMediumWeight,
+ fontSize = typeScaleTokens.headlineMediumSize,
+ lineHeight = typeScaleTokens.headlineMediumLineHeight,
+ letterSpacing = typeScaleTokens.headlineMediumTracking,
+ )
+ val headlineSmall =
+ TextStyle(
+ fontFamily = typeScaleTokens.headlineSmallFont,
+ fontWeight = typeScaleTokens.headlineSmallWeight,
+ fontSize = typeScaleTokens.headlineSmallSize,
+ lineHeight = typeScaleTokens.headlineSmallLineHeight,
+ letterSpacing = typeScaleTokens.headlineSmallTracking,
+ )
+ val labelLarge =
+ TextStyle(
+ fontFamily = typeScaleTokens.labelLargeFont,
+ fontWeight = typeScaleTokens.labelLargeWeight,
+ fontSize = typeScaleTokens.labelLargeSize,
+ lineHeight = typeScaleTokens.labelLargeLineHeight,
+ letterSpacing = typeScaleTokens.labelLargeTracking,
+ )
+ val labelMedium =
+ TextStyle(
+ fontFamily = typeScaleTokens.labelMediumFont,
+ fontWeight = typeScaleTokens.labelMediumWeight,
+ fontSize = typeScaleTokens.labelMediumSize,
+ lineHeight = typeScaleTokens.labelMediumLineHeight,
+ letterSpacing = typeScaleTokens.labelMediumTracking,
+ )
+ val labelSmall =
+ TextStyle(
+ fontFamily = typeScaleTokens.labelSmallFont,
+ fontWeight = typeScaleTokens.labelSmallWeight,
+ fontSize = typeScaleTokens.labelSmallSize,
+ lineHeight = typeScaleTokens.labelSmallLineHeight,
+ letterSpacing = typeScaleTokens.labelSmallTracking,
+ )
+ val titleLarge =
+ TextStyle(
+ fontFamily = typeScaleTokens.titleLargeFont,
+ fontWeight = typeScaleTokens.titleLargeWeight,
+ fontSize = typeScaleTokens.titleLargeSize,
+ lineHeight = typeScaleTokens.titleLargeLineHeight,
+ letterSpacing = typeScaleTokens.titleLargeTracking,
+ )
+ val titleMedium =
+ TextStyle(
+ fontFamily = typeScaleTokens.titleMediumFont,
+ fontWeight = typeScaleTokens.titleMediumWeight,
+ fontSize = typeScaleTokens.titleMediumSize,
+ lineHeight = typeScaleTokens.titleMediumLineHeight,
+ letterSpacing = typeScaleTokens.titleMediumTracking,
+ )
+ val titleSmall =
+ TextStyle(
+ fontFamily = typeScaleTokens.titleSmallFont,
+ fontWeight = typeScaleTokens.titleSmallWeight,
+ fontSize = typeScaleTokens.titleSmallSize,
+ lineHeight = typeScaleTokens.titleSmallLineHeight,
+ letterSpacing = typeScaleTokens.titleSmallTracking,
+ )
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index c540f0f7d557..e138ef8a1ea8 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -20,6 +20,7 @@ import android.graphics.Rect
import android.icu.text.NumberFormat
import android.util.TypedValue
import android.view.LayoutInflater
+import android.view.View
import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import com.android.systemui.customization.R
@@ -151,9 +152,15 @@ class DefaultClockController(
view: AnimatableClockView,
) : DefaultClockFaceController(view) {
override fun recomputePadding(targetRegion: Rect?) {
- // Ignore Target Region until top padding fixed in aod
+ // We center the view within the targetRegion instead of within the parent
+ // view by computing the difference and adding that to the padding.
+ val parent = view.parent
+ val yDiff =
+ if (targetRegion != null && parent is View && parent.isLaidOut())
+ targetRegion.centerY() - parent.height / 2f
+ else 0f
val lp = view.getLayoutParams() as FrameLayout.LayoutParams
- lp.topMargin = (-0.5f * view.bottom).toInt()
+ lp.topMargin = (-0.5f * view.bottom + yDiff).toInt()
view.setLayoutParams(lp)
}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 218c5cc9b7fe..b49afeef09f3 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -35,7 +35,6 @@
android:visibility="invisible" />
<FrameLayout
android:id="@+id/lockscreen_clock_view_large"
- android:layout_marginTop="@dimen/keyguard_large_clock_top_margin"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index da485a99c29b..cb704fdefb84 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -61,25 +61,25 @@
<!-- SIM messages --><skip />
<!-- When the user inserts a sim card from an unsupported network, it becomes network locked -->
<string name="keyguard_network_locked_message">Network locked</string>
- <!-- Shown when there is no SIM card. -->
- <string name="keyguard_missing_sim_message_short">No SIM card</string>
- <!-- Shown to ask the user to insert a SIM card. -->
- <string name="keyguard_missing_sim_instructions">Insert a SIM card.</string>
- <!-- Shown to ask the user to insert a SIM card when sim is missing or not readable. -->
- <string name="keyguard_missing_sim_instructions_long">The SIM card is missing or not readable. Insert a SIM card.</string>
- <!-- Shown when SIM card is permanently disabled. -->
- <string name="keyguard_permanent_disabled_sim_message_short">Unusable SIM card.</string>
- <!-- Shown to inform the user to SIM card is permanently disabled. -->
- <string name="keyguard_permanent_disabled_sim_instructions">Your SIM card has been permanently disabled.\n
- Contact your wireless service provider for another SIM card.</string>
+ <!-- Shown when there is no SIM. -->
+ <string name="keyguard_missing_sim_message_short">No SIM</string>
+ <!-- Shown to ask the user to add a SIM. -->
+ <string name="keyguard_missing_sim_instructions">Add a SIM.</string>
+ <!-- Shown to ask the user to add a SIM when sim is missing or not readable. -->
+ <string name="keyguard_missing_sim_instructions_long">The SIM is missing or not readable. Add a SIM.</string>
+ <!-- Shown when SIM is permanently disabled. -->
+ <string name="keyguard_permanent_disabled_sim_message_short">Unusable SIM.</string>
+ <!-- Shown to inform the user to SIM is permanently deactivated. -->
+ <string name="keyguard_permanent_disabled_sim_instructions">Your SIM has been permanently deactivated.\n
+ Contact your wireless service provider for another SIM.</string>
<!-- Shown to tell the user that their SIM is locked and they must unlock it. -->
- <string name="keyguard_sim_locked_message">SIM card is locked.</string>
+ <string name="keyguard_sim_locked_message">SIM is locked.</string>
<!-- When the user enters a wrong sim pin too many times, it becomes PUK locked (Pin Unlock Kode) -->
- <string name="keyguard_sim_puk_locked_message">SIM card is PUK-locked.</string>
+ <string name="keyguard_sim_puk_locked_message">SIM is PUK-locked.</string>
<!-- For the unlock screen, When the user enters a sim unlock code, it takes a little while to check
whether it is valid, and to unlock the sim if it is valid. we display a
progress dialog in the meantime. this is the emssage. -->
- <string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- Composes together the carrier name and the SIM card locked message. Example: CarrierName (SIM LOCKED) -->
<string name="keyguard_carrier_name_with_sim_locked_template" translatable="false"><xliff:g id="carrier">%s</xliff:g> (<xliff:g id="message">%s</xliff:g>)</string>
@@ -139,8 +139,8 @@
<string name="kg_puk_enter_pin_hint">Enter desired PIN code</string>
<!-- Message shown when the user needs to confirm the PIN they just entered in the PUK screen -->
<string name="kg_enter_confirm_pin_hint">Confirm desired PIN code</string>
- <!-- Message shown in dialog while the device is unlocking the SIM card -->
- <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <!-- Message shown in dialog while the device is unlocking the SIM -->
+ <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
<string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
<!-- Message shown when the user enters an invalid PUK code in the PUK screen -->
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index b71caef3f593..75c82867884f 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -28,10 +28,10 @@
<!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
<string name="inattentive_sleep_warning_message" product="default">The device will soon turn off; press to keep it on.</string>
- <!-- Shown when there is no SIM card. -->
- <string name="keyguard_missing_sim_message" product="tablet">No SIM card in tablet.</string>
- <!-- Shown when there is no SIM card. -->
- <string name="keyguard_missing_sim_message" product="default">No SIM card in phone.</string>
+ <!-- Shown when there is no SIM. -->
+ <string name="keyguard_missing_sim_message" product="tablet">No SIM in tablet.</string>
+ <!-- Shown when there is no SIM. -->
+ <string name="keyguard_missing_sim_message" product="default">No SIM in phone.</string>
<!-- String shown in PUK screen when PIN codes don't match -->
<string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 0e9abee2f050..9134f96f59e1 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -102,6 +102,7 @@
android:layout_margin="@dimen/overlay_border_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ app:layout_constraintHorizontal_bias="0"
app:layout_constraintBottom_toBottomOf="@id/preview_border"
app:layout_constraintStart_toStartOf="@id/preview_border"
app:layout_constraintEnd_toEndOf="@id/preview_border"
diff --git a/packages/SystemUI/res/layout/media_output_list_group_divider.xml b/packages/SystemUI/res/layout/media_output_list_group_divider.xml
new file mode 100644
index 000000000000..5e96866c0a9a
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_output_list_group_divider.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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/device_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="36dp"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="56dp"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textSize="16sp"/>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index 88429925eed0..65983b79570e 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -100,6 +100,7 @@
android:background="@drawable/overlay_preview_background"
android:adjustViewBounds="true"
android:clickable="true"
+ app:layout_constraintHorizontal_bias="0"
app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
app:layout_constraintStart_toStartOf="@id/screenshot_preview_border"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"
diff --git a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
deleted file mode 100644
index e4b6e0778664..000000000000
--- a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-precision mediump float;
-
-// The actual wallpaper texture.
-uniform sampler2D uTexture;
-
-varying vec2 vTextureCoordinates;
-
-void main() {
- // gets the pixel value of the wallpaper for this uv coordinates on screen.
- gl_FragColor = texture2D(uTexture, vTextureCoordinates);
-} \ No newline at end of file
diff --git a/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl
deleted file mode 100644
index 4393e2bb0ebf..000000000000
--- a/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl
+++ /dev/null
@@ -1,8 +0,0 @@
-attribute vec4 aPosition;
-attribute vec2 aTextureCoordinates;
-varying vec2 vTextureCoordinates;
-
-void main() {
- vTextureCoordinates = aTextureCoordinates;
- gl_Position = aPosition;
-} \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
index e226d58203f4..b057fe422fc4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
@@ -362,8 +362,7 @@ public class PluginActionManager<T extends Plugin> {
nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
mNotificationManager.notify(SystemMessage.NOTE_PLUGIN, nb.build());
// TODO: Warn user.
- Log.w(TAG, "Plugin has invalid interface version " + e.getActualVersion()
- + ", expected " + e.getExpectedVersion());
+ Log.w(TAG, "Error loading plugin; " + e.getMessage());
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
index 5883b6c0e723..b92715516a75 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
@@ -39,7 +39,6 @@ public class PreviewPositionHelper {
private boolean mIsOrientationChanged;
private SplitBounds mSplitBounds;
private int mDesiredStagePosition;
- private boolean mTaskbarInApp;
public Matrix getMatrix() {
return mMatrix;
@@ -58,10 +57,6 @@ public class PreviewPositionHelper {
mDesiredStagePosition = desiredStagePosition;
}
- public void setTaskbarInApp(boolean taskbarInApp) {
- mTaskbarInApp = taskbarInApp;
- }
-
/**
* Updates the matrix based on the provided parameters
*/
@@ -79,34 +74,21 @@ public class PreviewPositionHelper {
float scaledTaskbarSize;
float canvasScreenRatio;
if (mSplitBounds != null) {
- float fullscreenTaskWidth;
- float fullscreenTaskHeight;
-
- float taskPercent;
if (mSplitBounds.appsStackedVertically) {
- taskPercent = mDesiredStagePosition != STAGE_POSITION_TOP_OR_LEFT
- ? mSplitBounds.topTaskPercent
- : (1 - (mSplitBounds.topTaskPercent + mSplitBounds.dividerHeightPercent));
- // Scale portrait height to that of the actual screen
- fullscreenTaskHeight = screenHeightPx * taskPercent;
- if (mTaskbarInApp) {
- canvasScreenRatio = canvasHeight / fullscreenTaskHeight;
+ if (mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+ // Top app isn't cropped at all by taskbar
+ canvasScreenRatio = 0;
} else {
- if (mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
- // Top app isn't cropped at all by taskbar
- canvasScreenRatio = 0;
- } else {
- // Same as fullscreen ratio
- canvasScreenRatio = (float) canvasWidth / screenWidthPx;
- }
+ // Same as fullscreen ratio
+ canvasScreenRatio = (float) canvasWidth / screenWidthPx;
}
} else {
// For landscape, scale the width
- taskPercent = mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT
+ float taskPercent = mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT
? mSplitBounds.leftTaskPercent
: (1 - (mSplitBounds.leftTaskPercent + mSplitBounds.dividerWidthPercent));
// Scale landscape width to that of actual screen
- fullscreenTaskWidth = screenWidthPx * taskPercent;
+ float fullscreenTaskWidth = screenWidthPx * taskPercent;
canvasScreenRatio = canvasWidth / fullscreenTaskWidth;
}
} else {
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 87e9d5630b74..8f38e5800015 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -15,6 +15,7 @@
*/
package com.android.keyguard
+import android.app.WallpaperManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@@ -100,9 +101,13 @@ open class ClockEventController @Inject constructor(
private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING)
private fun updateColors() {
+
if (regionSamplingEnabled && smallRegionSampler != null && largeRegionSampler != null) {
- smallClockIsDark = smallRegionSampler!!.currentRegionDarkness().isDark
- largeClockIsDark = largeRegionSampler!!.currentRegionDarkness().isDark
+ val wallpaperManager = WallpaperManager.getInstance(context)
+ if (!wallpaperManager.lockScreenWallpaperExists()) {
+ smallClockIsDark = smallRegionSampler!!.currentRegionDarkness().isDark
+ largeClockIsDark = largeRegionSampler!!.currentRegionDarkness().isDark
+ }
} else {
val isLightTheme = TypedValue()
context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 7da27b1d6898..860c8e3a9f77 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -260,8 +260,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
if (reason != PROMPT_REASON_NONE) {
int promtReasonStringRes = mView.getPromptReasonStringRes(reason);
if (promtReasonStringRes != 0) {
- mMessageAreaController.setMessage(
- mView.getResources().getString(promtReasonStringRes), false);
+ mMessageAreaController.setMessage(promtReasonStringRes);
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index e6aae9bc461a..6ce84a94cc87 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -78,6 +78,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private int mCurrentClockSize = SMALL;
private int mKeyguardSmallClockTopMargin = 0;
+ private int mKeyguardLargeClockTopMargin = 0;
private final ClockRegistry.ClockChangeListener mClockChangedListener;
private ViewGroup mStatusArea;
@@ -164,6 +165,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mClockEventController.registerListeners(mView);
mKeyguardSmallClockTopMargin =
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
+ mKeyguardLargeClockTopMargin =
+ mView.getResources().getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin);
if (mOnlyClock) {
View ksv = mView.findViewById(R.id.keyguard_slice_view);
@@ -246,6 +249,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mView.onDensityOrFontScaleChanged();
mKeyguardSmallClockTopMargin =
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
+ mKeyguardLargeClockTopMargin =
+ mView.getResources().getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin);
mView.updateClockTargetRegions();
}
@@ -324,10 +329,18 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
+ // This gets the expected clock bottom if mLargeClockFrame had a top margin, but it's
+ // top margin only contributed to height and didn't move the top of the view (as this
+ // was the computation previously). As we no longer have a margin, we add this back
+ // into the computation manually.
int frameHeight = mLargeClockFrame.getHeight();
int clockHeight = clock.getLargeClock().getView().getHeight();
- return frameHeight / 2 + clockHeight / 2;
+ return frameHeight / 2 + clockHeight / 2 + mKeyguardLargeClockTopMargin / -2;
} else {
+ // This is only called if we've never shown the large clock as the frame is inflated
+ // with 'gone', but then the visibility is never set when it is animated away by
+ // KeyguardClockSwitch, instead it is removed from the view hierarchy.
+ // TODO(b/261755021): Cleanup Large Frame Visibility
int clockHeight = clock.getSmallClock().getView().getHeight();
return clockHeight + statusBarHeaderHeight + mKeyguardSmallClockTopMargin;
}
@@ -345,11 +358,15 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
return clock.getLargeClock().getView().getHeight();
} else {
+ // Is not called except in certain edge cases, see comment in getClockBottom
+ // TODO(b/261755021): Cleanup Large Frame Visibility
return clock.getSmallClock().getView().getHeight();
}
}
boolean isClockTopAligned() {
+ // Returns false except certain edge cases, see comment in getClockBottom
+ // TODO(b/261755021): Cleanup Large Frame Visibility
return mLargeClockFrame.getVisibility() != View.VISIBLE;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 53b569af29e1..2e9ad5868eba 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -143,9 +143,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
public void startAppearAnimation() {
if (TextUtils.isEmpty(mMessageAreaController.getMessage())) {
- mMessageAreaController.setMessage(
- mView.getResources().getString(getInitialMessageResId()),
- /* animate= */ false);
+ mMessageAreaController.setMessage(getInitialMessageResId());
}
mView.startAppearAnimation();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 67e3400670ba..5d86ccd5409e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -52,7 +52,6 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
private int mYTransOffset;
private View mBouncerMessageView;
@DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
- public static final long ANIMATION_DURATION = 650;
public KeyguardPINView(Context context) {
this(context, null);
@@ -182,7 +181,7 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
if (mAppearAnimator.isRunning()) {
mAppearAnimator.cancel();
}
- mAppearAnimator.setDuration(ANIMATION_DURATION);
+ mAppearAnimator.setDuration(650);
mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
mAppearAnimator.start();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5d7a6f122e69..8f3484a0c99b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -36,11 +36,8 @@ import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static java.lang.Integer.max;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
@@ -970,23 +967,11 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
}
mUserSwitcherViewGroup.setAlpha(0f);
- ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
- int yTrans = mView.getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry);
- animator.setInterpolator(Interpolators.STANDARD_DECELERATE);
- animator.setDuration(650);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mUserSwitcherViewGroup.setAlpha(1f);
- mUserSwitcherViewGroup.setTranslationY(0f);
- }
- });
- animator.addUpdateListener(animation -> {
- float value = (float) animation.getAnimatedValue();
- mUserSwitcherViewGroup.setAlpha(value);
- mUserSwitcherViewGroup.setTranslationY(yTrans - yTrans * value);
- });
- animator.start();
+ ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mUserSwitcherViewGroup, View.ALPHA,
+ 1f);
+ alphaAnim.setInterpolator(Interpolators.ALPHA_IN);
+ alphaAnim.setDuration(500);
+ alphaAnim.start();
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 9e58500c7206..886d110de369 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -54,35 +54,6 @@ class KeyguardLogger @Inject constructor(@KeyguardLog private val buffer: LogBuf
buffer.log(TAG, INFO, { str1 = arg.toString() }, { "$msg: $str1" })
}
- // TODO: remove after b/237743330 is fixed
- fun logStatusBarCalculatedAlpha(alpha: Float) {
- buffer.log(TAG, DEBUG, { double1 = alpha.toDouble() }, { "Calculated new alpha: $double1" })
- }
-
- // TODO: remove after b/237743330 is fixed
- fun logStatusBarExplicitAlpha(alpha: Float) {
- buffer.log(
- TAG,
- DEBUG,
- { double1 = alpha.toDouble() },
- { "new mExplicitAlpha value: $double1" }
- )
- }
-
- // TODO: remove after b/237743330 is fixed
- fun logStatusBarAlphaVisibility(visibility: Int, alpha: Float, state: String) {
- buffer.log(
- TAG,
- DEBUG,
- {
- int1 = visibility
- double1 = alpha.toDouble()
- str1 = state
- },
- { "changing visibility to $int1 with alpha $double1 in state: $str1" }
- )
- }
-
@JvmOverloads
fun logBiometricMessage(
@CompileTimeConstant context: String,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index 1e14763e57d5..e2a9d5456a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -25,6 +25,9 @@ import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.OvershootInterpolator;
+import android.view.animation.TranslateAnimation;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
@@ -33,6 +36,7 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.util.HashMap;
@@ -55,7 +59,11 @@ class MenuAnimationController {
private static final float SPRING_AFTER_FLING_DAMPING_RATIO = 0.85f;
private static final float SPRING_STIFFNESS = 700f;
private static final float ESCAPE_VELOCITY = 750f;
+ // Make tucked animation by using translation X relative to the view itself.
+ private static final float ANIMATION_TO_X_VALUE = 0.5f;
+ private static final int ANIMATION_START_OFFSET_MS = 600;
+ private static final int ANIMATION_DURATION_MS = 600;
private static final int FADE_OUT_DURATION_MS = 1000;
private static final int FADE_EFFECT_DURATION_MS = 3000;
@@ -64,10 +72,12 @@ class MenuAnimationController {
private final Handler mHandler;
private boolean mIsFadeEffectEnabled;
private DismissAnimationController.DismissCallback mDismissCallback;
+ private Runnable mSpringAnimationsEndAction;
// Cache the animations state of {@link DynamicAnimation.TRANSLATION_X} and {@link
// DynamicAnimation.TRANSLATION_Y} to be well controlled by the touch handler
- private final HashMap<DynamicAnimation.ViewProperty, DynamicAnimation> mPositionAnimations =
+ @VisibleForTesting
+ final HashMap<DynamicAnimation.ViewProperty, DynamicAnimation> mPositionAnimations =
new HashMap<>();
MenuAnimationController(MenuView menuView) {
@@ -102,6 +112,13 @@ class MenuAnimationController {
}
}
+ /**
+ * Sets the action to be called when the all dynamic animations are completed.
+ */
+ void setSpringAnimationsEndAction(Runnable runnable) {
+ mSpringAnimationsEndAction = runnable;
+ }
+
void setDismissCallback(
DismissAnimationController.DismissCallback dismissCallback) {
mDismissCallback = dismissCallback;
@@ -192,7 +209,7 @@ class MenuAnimationController {
? bounds.right
: bounds.bottom;
- final FlingAnimation flingAnimation = new FlingAnimation(mMenuView, menuPositionProperty);
+ final FlingAnimation flingAnimation = createFlingAnimation(mMenuView, menuPositionProperty);
flingAnimation.setFriction(friction)
.setStartVelocity(velocity)
.setMinValue(Math.min(currentValue, min))
@@ -217,7 +234,14 @@ class MenuAnimationController {
flingAnimation.start();
}
- private void springMenuWith(DynamicAnimation.ViewProperty property, SpringForce spring,
+ @VisibleForTesting
+ FlingAnimation createFlingAnimation(MenuView menuView,
+ MenuPositionProperty menuPositionProperty) {
+ return new FlingAnimation(menuView, menuPositionProperty);
+ }
+
+ @VisibleForTesting
+ void springMenuWith(DynamicAnimation.ViewProperty property, SpringForce spring,
float velocity, float finalPosition) {
final MenuPositionProperty menuPositionProperty = new MenuPositionProperty(property);
final SpringAnimation springAnimation =
@@ -228,8 +252,13 @@ class MenuAnimationController {
return;
}
- onSpringAnimationEnd(new PointF(mMenuView.getTranslationX(),
- mMenuView.getTranslationY()));
+ final boolean areAnimationsRunning =
+ mPositionAnimations.values().stream().anyMatch(
+ DynamicAnimation::isRunning);
+ if (!areAnimationsRunning) {
+ onSpringAnimationsEnd(new PointF(mMenuView.getTranslationX(),
+ mMenuView.getTranslationY()));
+ }
})
.setStartVelocity(velocity);
@@ -332,11 +361,15 @@ class MenuAnimationController {
.start();
}
- private void onSpringAnimationEnd(PointF position) {
+ private void onSpringAnimationsEnd(PointF position) {
mMenuView.onBoundsInParentChanged((int) position.x, (int) position.y);
constrainPositionAndUpdate(position);
fadeOutIfEnabled();
+
+ if (mSpringAnimationsEndAction != null) {
+ mSpringAnimationsEndAction.run();
+ }
}
private void constrainPositionAndUpdate(PointF position) {
@@ -387,6 +420,26 @@ class MenuAnimationController {
mHandler.removeCallbacksAndMessages(/* token= */ null);
}
+ void startTuckedAnimationPreview() {
+ fadeInNowIfEnabled();
+
+ final float toXValue = isOnLeftSide()
+ ? -ANIMATION_TO_X_VALUE
+ : ANIMATION_TO_X_VALUE;
+ final TranslateAnimation animation =
+ new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
+ Animation.RELATIVE_TO_SELF, toXValue,
+ Animation.RELATIVE_TO_SELF, 0,
+ Animation.RELATIVE_TO_SELF, 0);
+ animation.setDuration(ANIMATION_DURATION_MS);
+ animation.setRepeatMode(Animation.REVERSE);
+ animation.setInterpolator(new OvershootInterpolator());
+ animation.setRepeatCount(Animation.INFINITE);
+ animation.setStartOffset(ANIMATION_START_OFFSET_MS);
+
+ mMenuView.startAnimation(animation);
+ }
+
private Handler createUiHandler() {
return new Handler(requireNonNull(Looper.myLooper(), "looper must not be null"));
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java
new file mode 100644
index 000000000000..440053450d2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static android.util.TypedValue.COMPLEX_UNIT_PX;
+import static android.view.View.MeasureSpec.AT_MOST;
+import static android.view.View.MeasureSpec.UNSPECIFIED;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.CornerPathEffect;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.text.method.LinkMovementMethod;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+import com.android.systemui.recents.TriangleShape;
+
+/**
+ * The tooltip view shows the information about the operation of the anchor view {@link MenuView}
+ * . It's just shown on the left or right of the anchor view.
+ */
+@SuppressLint("ViewConstructor")
+class MenuEduTooltipView extends FrameLayout {
+ private int mFontSize;
+ private int mTextViewMargin;
+ private int mTextViewPadding;
+ private int mTextViewCornerRadius;
+ private int mArrowMargin;
+ private int mArrowWidth;
+ private int mArrowHeight;
+ private int mArrowCornerRadius;
+ private int mColorAccentPrimary;
+ private View mArrowLeftView;
+ private View mArrowRightView;
+ private TextView mMessageView;
+ private final MenuViewAppearance mMenuViewAppearance;
+
+ MenuEduTooltipView(@NonNull Context context, MenuViewAppearance menuViewAppearance) {
+ super(context);
+
+ mMenuViewAppearance = menuViewAppearance;
+
+ updateResources();
+ initViews();
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ updateResources();
+ updateMessageView();
+ updateArrowView();
+
+ updateLocationAndVisibility();
+ }
+
+ void show(CharSequence message) {
+ mMessageView.setText(message);
+
+ updateLocationAndVisibility();
+ }
+
+ void updateLocationAndVisibility() {
+ final boolean isTooltipOnRightOfAnchor = mMenuViewAppearance.isMenuOnLeftSide();
+ updateArrowVisibilityWith(isTooltipOnRightOfAnchor);
+ updateLocationWith(getMenuBoundsInParent(), isTooltipOnRightOfAnchor);
+ }
+
+ /**
+ * Gets the bounds of the {@link MenuView}. Besides, its parent view {@link MenuViewLayer} is
+ * also the root view of the tooltip view.
+ *
+ * @return The menu bounds based on its parent view.
+ */
+ private Rect getMenuBoundsInParent() {
+ final Rect bounds = new Rect();
+ final PointF position = mMenuViewAppearance.getMenuPosition();
+
+ bounds.set((int) position.x, (int) position.y,
+ (int) position.x + mMenuViewAppearance.getMenuWidth(),
+ (int) position.y + mMenuViewAppearance.getMenuHeight());
+
+ return bounds;
+ }
+
+ private void updateResources() {
+ final Resources res = getResources();
+
+ mArrowWidth =
+ res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_width);
+ mArrowHeight =
+ res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_height);
+ mArrowMargin =
+ res.getDimensionPixelSize(
+ R.dimen.accessibility_floating_tooltip_arrow_margin);
+ mArrowCornerRadius =
+ res.getDimensionPixelSize(
+ R.dimen.accessibility_floating_tooltip_arrow_corner_radius);
+ mFontSize =
+ res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_font_size);
+ mTextViewMargin =
+ res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_margin);
+ mTextViewPadding =
+ res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_padding);
+ mTextViewCornerRadius =
+ res.getDimensionPixelSize(
+ R.dimen.accessibility_floating_tooltip_text_corner_radius);
+ mColorAccentPrimary = Utils.getColorAttrDefaultColor(getContext(),
+ com.android.internal.R.attr.colorAccentPrimary);
+ }
+
+ private void updateLocationWith(Rect anchorBoundsInParent, boolean isTooltipOnRightOfAnchor) {
+ final int widthSpec = MeasureSpec.makeMeasureSpec(
+ getAvailableTextViewWidth(isTooltipOnRightOfAnchor), AT_MOST);
+ final int heightSpec = MeasureSpec.makeMeasureSpec(/* size= */ 0, UNSPECIFIED);
+ mMessageView.measure(widthSpec, heightSpec);
+ final LinearLayout.LayoutParams textViewParams =
+ (LinearLayout.LayoutParams) mMessageView.getLayoutParams();
+ textViewParams.width = mMessageView.getMeasuredWidth();
+ mMessageView.setLayoutParams(textViewParams);
+
+ final int layoutWidth = mMessageView.getMeasuredWidth() + mArrowWidth + mArrowMargin;
+ setTranslationX(isTooltipOnRightOfAnchor
+ ? anchorBoundsInParent.right
+ : anchorBoundsInParent.left - layoutWidth);
+
+ setTranslationY(anchorBoundsInParent.centerY() - (mMessageView.getMeasuredHeight() / 2.0f));
+ }
+
+ private void updateMessageView() {
+ mMessageView.setTextSize(COMPLEX_UNIT_PX, mFontSize);
+ mMessageView.setPadding(mTextViewPadding, mTextViewPadding, mTextViewPadding,
+ mTextViewPadding);
+
+ final GradientDrawable gradientDrawable = (GradientDrawable) mMessageView.getBackground();
+ gradientDrawable.setCornerRadius(mTextViewCornerRadius);
+ gradientDrawable.setColor(mColorAccentPrimary);
+ }
+
+ private void updateArrowView() {
+ drawArrow(mArrowLeftView, /* isPointingLeft= */ true);
+ drawArrow(mArrowRightView, /* isPointingLeft= */ false);
+ }
+
+ private void updateArrowVisibilityWith(boolean isTooltipOnRightOfAnchor) {
+ if (isTooltipOnRightOfAnchor) {
+ mArrowLeftView.setVisibility(VISIBLE);
+ mArrowRightView.setVisibility(GONE);
+ } else {
+ mArrowLeftView.setVisibility(GONE);
+ mArrowRightView.setVisibility(VISIBLE);
+ }
+ }
+
+ private void drawArrow(View arrowView, boolean isPointingLeft) {
+ final TriangleShape triangleShape =
+ TriangleShape.createHorizontal(mArrowWidth, mArrowHeight, isPointingLeft);
+ final ShapeDrawable arrowDrawable = new ShapeDrawable(triangleShape);
+ final Paint arrowPaint = arrowDrawable.getPaint();
+ arrowPaint.setColor(mColorAccentPrimary);
+
+ final CornerPathEffect effect = new CornerPathEffect(mArrowCornerRadius);
+ arrowPaint.setPathEffect(effect);
+
+ arrowView.setBackground(arrowDrawable);
+ }
+
+ private void initViews() {
+ final View contentView = LayoutInflater.from(getContext()).inflate(
+ R.layout.accessibility_floating_menu_tooltip, /* root= */ this, /* attachToRoot= */
+ false);
+
+ mMessageView = contentView.findViewById(R.id.text);
+ mMessageView.setMovementMethod(LinkMovementMethod.getInstance());
+
+ mArrowLeftView = contentView.findViewById(R.id.arrow_left);
+ mArrowRightView = contentView.findViewById(R.id.arrow_right);
+
+ updateMessageView();
+ updateArrowView();
+
+ addView(contentView);
+ }
+
+ private int getAvailableTextViewWidth(boolean isOnRightOfAnchor) {
+ final PointF position = mMenuViewAppearance.getMenuPosition();
+ final int availableWidth = isOnRightOfAnchor
+ ? mMenuViewAppearance.getMenuDraggableBounds().width() - (int) position.x
+ : (int) position.x;
+
+ return availableWidth - mArrowWidth - mArrowMargin - mTextViewMargin;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
index 5bc7406bb9d0..05e1d3f0e126 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
@@ -17,6 +17,7 @@
package com.android.systemui.accessibility.floatingmenu;
import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED;
+import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT;
import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY;
import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE;
import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
@@ -28,6 +29,7 @@ import static com.android.systemui.accessibility.floatingmenu.MenuFadeEffectInfo
import static com.android.systemui.accessibility.floatingmenu.MenuViewAppearance.MenuSizeType.SMALL;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
@@ -40,6 +42,8 @@ import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -52,12 +56,24 @@ class MenuInfoRepository {
@FloatRange(from = 0.0, to = 1.0)
private static final float DEFAULT_MENU_POSITION_Y_PERCENT = 0.77f;
private static final boolean DEFAULT_MOVE_TO_TUCKED_VALUE = false;
+ private static final boolean DEFAULT_HAS_SEEN_DOCK_TOOLTIP_VALUE = false;
+ private static final int DEFAULT_MIGRATION_TOOLTIP_VALUE_PROMPT = MigrationPrompt.DISABLED;
private final Context mContext;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final OnSettingsContentsChanged mSettingsContentsCallback;
private Position mPercentagePosition;
+ @IntDef({
+ MigrationPrompt.DISABLED,
+ MigrationPrompt.ENABLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface MigrationPrompt {
+ int DISABLED = 0;
+ int ENABLED = 1;
+ }
+
private final ContentObserver mMenuTargetFeaturesContentObserver =
new ContentObserver(mHandler) {
@Override
@@ -99,6 +115,19 @@ class MenuInfoRepository {
DEFAULT_MOVE_TO_TUCKED_VALUE));
}
+ void loadDockTooltipVisibility(OnInfoReady<Boolean> callback) {
+ callback.onReady(Prefs.getBoolean(mContext,
+ Prefs.Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP,
+ DEFAULT_HAS_SEEN_DOCK_TOOLTIP_VALUE));
+ }
+
+ void loadMigrationTooltipVisibility(OnInfoReady<Boolean> callback) {
+ callback.onReady(Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
+ DEFAULT_MIGRATION_TOOLTIP_VALUE_PROMPT, UserHandle.USER_CURRENT)
+ == MigrationPrompt.ENABLED);
+ }
+
void loadMenuPosition(OnInfoReady<Position> callback) {
callback.onReady(mPercentagePosition);
}
@@ -131,6 +160,18 @@ class MenuInfoRepository {
percentagePosition.toString());
}
+ void updateDockTooltipVisibility(boolean hasSeen) {
+ Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP,
+ hasSeen);
+ }
+
+ void updateMigrationTooltipVisibility(boolean visible) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
+ visible ? MigrationPrompt.ENABLED : MigrationPrompt.DISABLED,
+ UserHandle.USER_CURRENT);
+ }
+
private Position getStartPosition() {
final String absolutePositionString = Prefs.getString(mContext,
Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, /* defaultValue= */ null);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
index bc3cf0a6bab0..8a31142a0212 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
@@ -25,6 +25,8 @@ import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
+import java.util.Optional;
+
/**
* Controls the all touch events of the accessibility target features view{@link RecyclerView} in
* the {@link MenuView}. And then compute the gestures' velocity for fling and spring
@@ -39,6 +41,7 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener {
private boolean mIsDragging = false;
private float mTouchSlop;
private final DismissAnimationController mDismissAnimationController;
+ private Optional<Runnable> mOnActionDownEnd = Optional.empty();
MenuListViewTouchHandler(MenuAnimationController menuAnimationController,
DismissAnimationController dismissAnimationController) {
@@ -65,6 +68,8 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener {
mMenuAnimationController.cancelAnimations();
mDismissAnimationController.maybeConsumeDownMotionEvent(motionEvent);
+
+ mOnActionDownEnd.ifPresent(Runnable::run);
break;
case MotionEvent.ACTION_MOVE:
if (mIsDragging || Math.hypot(dx, dy) > mTouchSlop) {
@@ -125,6 +130,10 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener {
// Do nothing
}
+ void setOnActionDownEndListener(Runnable onActionDownEndListener) {
+ mOnActionDownEnd = Optional.ofNullable(onActionDownEndListener);
+ }
+
/**
* Adds a movement to the velocity tracker using raw screen coordinates.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
index a7cdeab7c127..3cd250fb4575 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
@@ -293,7 +293,7 @@ class MenuViewAppearance {
return bounds;
}
- private boolean isMenuOnLeftSide() {
+ boolean isMenuOnLeftSide() {
return mPercentagePosition.getPercentageX() < 0.5f;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index c42943cf56e2..6f5b39cc7d56 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -20,6 +20,7 @@ import static android.view.WindowInsets.Type.ime;
import static androidx.core.view.WindowInsetsCompat.Type;
+import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_BUTTON_COMPONENT_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE;
import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType;
import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
@@ -27,8 +28,10 @@ import static com.android.systemui.accessibility.floatingmenu.MenuMessageView.In
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
+import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
@@ -37,6 +40,8 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.PluralsMessageFormatter;
import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
@@ -45,6 +50,7 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.lifecycle.Observer;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
@@ -58,6 +64,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
/**
* The basic interactions with the child views {@link MenuView}, {@link DismissView}, and
@@ -66,11 +73,13 @@ import java.util.Map;
* message view would be shown and allowed users to undo it.
*/
@SuppressLint("ViewConstructor")
-class MenuViewLayer extends FrameLayout {
+class MenuViewLayer extends FrameLayout implements
+ ViewTreeObserver.OnComputeInternalInsetsListener, View.OnClickListener {
private static final int SHOW_MESSAGE_DELAY_MS = 3000;
private final WindowManager mWindowManager;
private final MenuView mMenuView;
+ private final MenuListViewTouchHandler mMenuListViewTouchHandler;
private final MenuMessageView mMessageView;
private final DismissView mDismissView;
private final MenuViewAppearance mMenuViewAppearance;
@@ -79,18 +88,38 @@ class MenuViewLayer extends FrameLayout {
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final IAccessibilityFloatingMenu mFloatingMenu;
private final DismissAnimationController mDismissAnimationController;
+ private final MenuViewModel mMenuViewModel;
+ private final Observer<Boolean> mDockTooltipObserver =
+ this::onDockTooltipVisibilityChanged;
+ private final Observer<Boolean> mMigrationTooltipObserver =
+ this::onMigrationTooltipVisibilityChanged;
private final Rect mImeInsetsRect = new Rect();
+ private boolean mIsMigrationTooltipShowing;
+ private boolean mShouldShowDockTooltip;
+ private Optional<MenuEduTooltipView> mEduTooltipView = Optional.empty();
@IntDef({
LayerIndex.MENU_VIEW,
LayerIndex.DISMISS_VIEW,
LayerIndex.MESSAGE_VIEW,
+ LayerIndex.TOOLTIP_VIEW,
})
@Retention(RetentionPolicy.SOURCE)
@interface LayerIndex {
int MENU_VIEW = 0;
int DISMISS_VIEW = 1;
int MESSAGE_VIEW = 2;
+ int TOOLTIP_VIEW = 3;
+ }
+
+ @StringDef({
+ TooltipType.MIGRATION,
+ TooltipType.DOCK,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface TooltipType {
+ String MIGRATION = "migration";
+ String DOCK = "dock";
}
@VisibleForTesting
@@ -125,12 +154,12 @@ class MenuViewLayer extends FrameLayout {
mAccessibilityManager = accessibilityManager;
mFloatingMenu = floatingMenu;
- final MenuViewModel menuViewModel = new MenuViewModel(context);
+ mMenuViewModel = new MenuViewModel(context);
mMenuViewAppearance = new MenuViewAppearance(context, windowManager);
- mMenuView = new MenuView(context, menuViewModel, mMenuViewAppearance);
+ mMenuView = new MenuView(context, mMenuViewModel, mMenuViewAppearance);
mMenuAnimationController = mMenuView.getMenuAnimationController();
mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage);
-
+ mMenuAnimationController.setSpringAnimationsEndAction(this::onSpringAnimationsEndAction);
mDismissView = new DismissView(context);
mDismissAnimationController = new DismissAnimationController(mDismissView, mMenuView);
mDismissAnimationController.setMagnetListener(new MagnetizedObject.MagnetListener() {
@@ -153,9 +182,9 @@ class MenuViewLayer extends FrameLayout {
}
});
- final MenuListViewTouchHandler menuListViewTouchHandler = new MenuListViewTouchHandler(
- mMenuAnimationController, mDismissAnimationController);
- mMenuView.addOnItemTouchListenerToList(menuListViewTouchHandler);
+ mMenuListViewTouchHandler = new MenuListViewTouchHandler(mMenuAnimationController,
+ mDismissAnimationController);
+ mMenuView.addOnItemTouchListenerToList(mMenuListViewTouchHandler);
mMessageView = new MenuMessageView(context);
@@ -210,7 +239,12 @@ class MenuViewLayer extends FrameLayout {
super.onAttachedToWindow();
mMenuView.show();
+ setOnClickListener(this);
setOnApplyWindowInsetsListener((view, insets) -> onWindowInsetsApplied(insets));
+ getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+ mMenuViewModel.getDockTooltipVisibilityData().observeForever(mDockTooltipObserver);
+ mMenuViewModel.getMigrationTooltipVisibilityData().observeForever(
+ mMigrationTooltipObserver);
mMessageView.setUndoListener(view -> undo());
mContext.registerComponentCallbacks(mDismissAnimationController);
}
@@ -220,11 +254,32 @@ class MenuViewLayer extends FrameLayout {
super.onDetachedFromWindow();
mMenuView.hide();
+ setOnClickListener(null);
setOnApplyWindowInsetsListener(null);
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+ mMenuViewModel.getDockTooltipVisibilityData().removeObserver(mDockTooltipObserver);
+ mMenuViewModel.getMigrationTooltipVisibilityData().removeObserver(
+ mMigrationTooltipObserver);
mHandler.removeCallbacksAndMessages(/* token= */ null);
mContext.unregisterComponentCallbacks(mDismissAnimationController);
}
+ @Override
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+ inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+
+ if (mEduTooltipView.isPresent()) {
+ final int x = (int) getX();
+ final int y = (int) getY();
+ inoutInfo.touchableRegion.union(new Rect(x, y, x + getWidth(), y + getHeight()));
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ mEduTooltipView.ifPresent(this::removeTooltip);
+ }
+
private WindowInsets onWindowInsetsApplied(WindowInsets insets) {
final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
final WindowInsets windowInsets = windowMetrics.getWindowInsets();
@@ -249,6 +304,78 @@ class MenuViewLayer extends FrameLayout {
return insets;
}
+ private void onMigrationTooltipVisibilityChanged(boolean visible) {
+ mIsMigrationTooltipShowing = visible;
+
+ if (mIsMigrationTooltipShowing) {
+ mEduTooltipView = Optional.of(new MenuEduTooltipView(mContext, mMenuViewAppearance));
+ mEduTooltipView.ifPresent(
+ view -> addTooltipView(view, getMigrationMessage(), TooltipType.MIGRATION));
+ }
+ }
+
+ private void onDockTooltipVisibilityChanged(boolean hasSeenTooltip) {
+ mShouldShowDockTooltip = !hasSeenTooltip;
+ }
+
+ private void onSpringAnimationsEndAction() {
+ if (mShouldShowDockTooltip) {
+ mEduTooltipView = Optional.of(new MenuEduTooltipView(mContext, mMenuViewAppearance));
+ mEduTooltipView.ifPresent(view -> addTooltipView(view,
+ getContext().getText(R.string.accessibility_floating_button_docking_tooltip),
+ TooltipType.DOCK));
+
+ mMenuAnimationController.startTuckedAnimationPreview();
+ }
+ }
+
+ private CharSequence getMigrationMessage() {
+ final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
+ ACCESSIBILITY_BUTTON_COMPONENT_NAME.flattenToShortString());
+
+ final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo(
+ AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
+ v -> {
+ getContext().startActivity(intent);
+ mEduTooltipView.ifPresent(this::removeTooltip);
+ });
+
+ final int textResId = R.string.accessibility_floating_button_migration_tooltip;
+
+ return AnnotationLinkSpan.linkify(getContext().getText(textResId), linkInfo);
+ }
+
+ private void addTooltipView(MenuEduTooltipView tooltipView, CharSequence message,
+ CharSequence tag) {
+ addView(tooltipView, LayerIndex.TOOLTIP_VIEW);
+
+ tooltipView.show(message);
+ tooltipView.setTag(tag);
+
+ mMenuListViewTouchHandler.setOnActionDownEndListener(
+ () -> mEduTooltipView.ifPresent(this::removeTooltip));
+ }
+
+ private void removeTooltip(View tooltipView) {
+ if (tooltipView.getTag().equals(TooltipType.MIGRATION)) {
+ mMenuViewModel.updateMigrationTooltipVisibility(/* visible= */ false);
+ mIsMigrationTooltipShowing = false;
+ }
+
+ if (tooltipView.getTag().equals(TooltipType.DOCK)) {
+ mMenuViewModel.updateDockTooltipVisibility(/* hasSeen= */ true);
+ mMenuView.clearAnimation();
+ mShouldShowDockTooltip = false;
+ }
+
+ removeView(tooltipView);
+
+ mMenuListViewTouchHandler.setOnActionDownEndListener(null);
+ mEduTooltipView = Optional.empty();
+ }
+
private void hideMenuAndShowMessage() {
final int delayTime = mAccessibilityManager.getRecommendedTimeoutMillis(
SHOW_MESSAGE_DELAY_MS,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java
index bd417877c124..5fea3b0ba2f9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java
@@ -36,6 +36,8 @@ class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
private final MutableLiveData<MenuFadeEffectInfo> mFadeEffectInfoData =
new MutableLiveData<>();
private final MutableLiveData<Boolean> mMoveToTuckedData = new MutableLiveData<>();
+ private final MutableLiveData<Boolean> mDockTooltipData = new MutableLiveData<>();
+ private final MutableLiveData<Boolean> mMigrationTooltipData = new MutableLiveData<>();
private final MutableLiveData<Position> mPercentagePositionData = new MutableLiveData<>();
private final MenuInfoRepository mInfoRepository;
@@ -66,11 +68,29 @@ class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
mInfoRepository.updateMenuSavingPosition(percentagePosition);
}
+ void updateDockTooltipVisibility(boolean hasSeen) {
+ mInfoRepository.updateDockTooltipVisibility(hasSeen);
+ }
+
+ void updateMigrationTooltipVisibility(boolean visible) {
+ mInfoRepository.updateMigrationTooltipVisibility(visible);
+ }
+
LiveData<Boolean> getMoveToTuckedData() {
mInfoRepository.loadMenuMoveToTucked(mMoveToTuckedData::setValue);
return mMoveToTuckedData;
}
+ LiveData<Boolean> getDockTooltipVisibilityData() {
+ mInfoRepository.loadDockTooltipVisibility(mDockTooltipData::setValue);
+ return mDockTooltipData;
+ }
+
+ LiveData<Boolean> getMigrationTooltipVisibilityData() {
+ mInfoRepository.loadMigrationTooltipVisibility(mMigrationTooltipData::setValue);
+ return mMigrationTooltipData;
+ }
+
LiveData<Position> getPercentagePositionData() {
mInfoRepository.loadMenuPosition(mPercentagePositionData::setValue);
return mPercentagePositionData;
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 6785a43600f2..9708d9a02edc 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -64,7 +64,7 @@ import javax.inject.Inject;
@SysUISingleton
public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController,
AppOpsManager.OnOpActiveChangedListener,
- AppOpsManager.OnOpNotedListener, IndividualSensorPrivacyController.Callback,
+ AppOpsManager.OnOpNotedInternalListener, IndividualSensorPrivacyController.Callback,
Dumpable {
// This is the minimum time that we will keep AppOps that are noted on record. If multiple
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/biometrics/TEST_MAPPING
deleted file mode 100644
index 794eba4d8de9..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/TEST_MAPPING
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "presubmit": [
- {
- // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
- "name": "SystemUIGoogleBiometricsScreenshotTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ]
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 7fd4d6ac1b34..1613ca1fd034 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -116,7 +116,7 @@ import kotlin.Unit;
@SysUISingleton
public class UdfpsController implements DozeReceiver, Dumpable {
private static final String TAG = "UdfpsController";
- private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
+ private static final long AOD_SEND_FINGER_UP_DELAY_MILLIS = 1000;
// Minimum required delay between consecutive touch logs in milliseconds.
private static final long MIN_TOUCH_LOG_INTERVAL = 50;
@@ -179,7 +179,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
// interrupt is being tracked and a timeout is used as a last resort to turn off high brightness
// mode.
private boolean mIsAodInterruptActive;
- @Nullable private Runnable mCancelAodTimeoutAction;
+ @Nullable private Runnable mCancelAodFingerUpAction;
private boolean mScreenOn;
private Runnable mAodInterruptRunnable;
private boolean mOnFingerDown;
@@ -281,6 +281,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
if (view != null && isOptical()) {
unconfigureDisplay(view);
}
+ tryAodSendFingerUp();
if (acquiredGood) {
mOverlay.onAcquiredGood();
}
@@ -901,12 +902,6 @@ public class UdfpsController implements DozeReceiver, Dumpable {
private void unconfigureDisplay(@NonNull UdfpsView view) {
if (view.isDisplayConfigured()) {
view.unconfigureDisplay();
-
- if (mCancelAodTimeoutAction != null) {
- mCancelAodTimeoutAction.run();
- mCancelAodTimeoutAction = null;
- }
- mIsAodInterruptActive = false;
}
}
@@ -946,8 +941,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
// ACTION_UP/ACTION_CANCEL, we need to be careful about not letting the screen
// accidentally remain in high brightness mode. As a mitigation, queue a call to
// cancel the fingerprint scan.
- mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::cancelAodInterrupt,
- AOD_INTERRUPT_TIMEOUT_MILLIS);
+ mCancelAodFingerUpAction = mFgExecutor.executeDelayed(this::tryAodSendFingerUp,
+ AOD_SEND_FINGER_UP_DELAY_MILLIS);
// using a hard-coded value for major and minor until it is available from the sensor
onFingerDown(requestId, screenX, screenY, minor, major);
};
@@ -981,15 +976,27 @@ public class UdfpsController implements DozeReceiver, Dumpable {
* sensors, this can result in illumination persisting for longer than necessary.
*/
@VisibleForTesting
- void cancelAodInterrupt() {
+ void tryAodSendFingerUp() {
if (!mIsAodInterruptActive) {
return;
}
+ cancelAodSendFingerUpAction();
if (mOverlay != null && mOverlay.getOverlayView() != null) {
onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView());
}
- mCancelAodTimeoutAction = null;
+ }
+
+ /**
+ * Cancels any scheduled AoD finger-up actions without triggered the finger-up action. Only
+ * call this method if the finger-up event has been guaranteed to have already occurred.
+ */
+ @VisibleForTesting
+ void cancelAodSendFingerUpAction() {
mIsAodInterruptActive = false;
+ if (mCancelAodFingerUpAction != null) {
+ mCancelAodFingerUpAction.run();
+ mCancelAodFingerUpAction = null;
+ }
}
private boolean isOptical() {
@@ -1151,6 +1158,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
if (isOptical()) {
unconfigureDisplay(view);
}
+ cancelAodSendFingerUpAction();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
index 66e5d7c4a3bc..dbe301df8e78 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
@@ -69,12 +69,14 @@ class ControlsServiceInfo(
private var resolved: Boolean = false
@WorkerThread
- fun resolvePanelActivity() {
+ fun resolvePanelActivity(
+ allowAllApps: Boolean = false
+ ) {
if (resolved) return
resolved = true
val validPackages = context.resources
.getStringArray(R.array.config_controlsPreferredPackages)
- if (componentName.packageName !in validPackages) return
+ if (componentName.packageName !in validPackages && !allowAllApps) return
panelActivity = _panelActivity?.let {
val resolveInfos = mPm.queryIntentActivitiesAsUser(
Intent().setComponent(it),
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index c6428ef6eb8e..c81a2c7e2ac6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -98,7 +98,9 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
backgroundExecutor.execute {
if (userChangeInProgress.get() > 0) return@execute
if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
- newServices.forEach(ControlsServiceInfo::resolvePanelActivity)
+ val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
+ newServices.forEach {
+ it.resolvePanelActivity(allowAllApps) }
}
if (newServices != availableServices) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 8b4b30c89b14..3644d4242a6f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -36,6 +36,8 @@ import android.app.job.JobScheduler;
import android.app.role.RoleManager;
import android.app.smartspace.SmartspaceManager;
import android.app.trust.TrustManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -616,4 +618,16 @@ public class FrameworkServicesModule {
static CameraManager provideCameraManager(Context context) {
return context.getSystemService(CameraManager.class);
}
+
+ @Provides
+ @Singleton
+ static BluetoothManager provideBluetoothManager(Context context) {
+ return context.getSystemService(BluetoothManager.class);
+ }
+
+ @Provides
+ @Singleton
+ static BluetoothAdapter provideBluetoothAdapter(BluetoothManager bluetoothManager) {
+ return bluetoothManager.getAdapter();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 6dc4f5c60108..68f4dbe53500 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -125,10 +125,10 @@ public interface SysUIComponent {
default void init() {
// Initialize components that have no direct tie to the dagger dependency graph,
// but are critical to this component's operation
- // TODO(b/205034537): I think this is a good idea?
getSysUIUnfoldComponent().ifPresent(c -> {
c.getUnfoldLightRevealOverlayAnimation().init();
c.getUnfoldTransitionWallpaperController().init();
+ c.getUnfoldHapticsPlayer();
});
getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
// No init method needed, just needs to be gotten so that it's created.
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 3a59f4b5436c..246528653380 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -40,6 +40,7 @@ import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
+import com.android.systemui.dreams.complication.dagger.ComplicationComponent;
import com.android.systemui.dreams.dagger.DreamModule;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
@@ -163,6 +164,7 @@ import dagger.Provides;
},
subcomponents = {
CentralSurfacesComponent.class,
+ ComplicationComponent.class,
NavigationBarComponent.class,
NotificationRowComponent.class,
DozeComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 0c14ed5c2164..5d21349fce11 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -28,6 +28,8 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.google.errorprone.annotations.CompileTimeConstant;
+
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -80,6 +82,13 @@ public class DozeLog implements Dumpable {
}
/**
+ * Log debug message to LogBuffer.
+ */
+ public void d(@CompileTimeConstant String msg) {
+ mLogger.log(msg);
+ }
+
+ /**
* Appends pickup wakeup event to the logs
*/
public void tracePickupWakeUp(boolean withinVibrationThreshold) {
@@ -88,6 +97,10 @@ public class DozeLog implements Dumpable {
: mPickupPulseNotNearVibrationStats).append();
}
+ public void traceSetIgnoreTouchWhilePulsing(boolean ignoreTouch) {
+ mLogger.logSetIgnoreTouchWhilePulsing(ignoreTouch);
+ }
+
/**
* Appends pulse started event to the logs.
* @param reason why the pulse started
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index b5dbe21a2cf7..d19c6ec01109 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -364,6 +364,14 @@ class DozeLogger @Inject constructor(
})
}
+ fun logSetIgnoreTouchWhilePulsing(ignoreTouchWhilePulsing: Boolean) {
+ buffer.log(TAG, DEBUG, {
+ bool1 = ignoreTouchWhilePulsing
+ }, {
+ "Prox changed while pulsing. setIgnoreTouchWhilePulsing=$bool1"
+ })
+ }
+
fun log(@CompileTimeConstant msg: String) {
buffer.log(TAG, DEBUG, msg)
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 5daf1ceaf592..3f9f14c620b5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -333,15 +333,18 @@ public class DozeTriggers implements DozeMachine.Part {
}
gentleWakeUp(pulseReason);
} else if (isUdfpsLongPress) {
- final State state = mMachine.getState();
- if (state == State.DOZE_AOD || state == State.DOZE) {
+ if (canPulse(mMachine.getState(), true)) {
+ mDozeLog.d("updfsLongPress - setting aodInterruptRunnable to run when "
+ + "the display is on");
// Since the gesture won't be received by the UDFPS view, we need to
// manually inject an event once the display is ON
mAodInterruptRunnable = () ->
- mAuthController.onAodInterrupt((int) screenX, (int) screenY,
- rawValues[3] /* major */, rawValues[4] /* minor */);
+ mAuthController.onAodInterrupt((int) screenX, (int) screenY,
+ rawValues[3] /* major */, rawValues[4] /* minor */);
+ } else {
+ mDozeLog.d("udfpsLongPress - Not sending aodInterrupt. "
+ + "Unsupported doze state.");
}
-
requestPulse(DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, true, null);
} else {
mDozeHost.extendPulse(pulseReason);
@@ -380,7 +383,7 @@ public class DozeTriggers implements DozeMachine.Part {
// when a new event is arriving. This means that a state transition might have happened
// and the proximity check is now obsolete.
if (mMachine.isExecutingTransition()) {
- Log.w(TAG, "onProximityFar called during transition. Ignoring sensor response.");
+ mDozeLog.d("onProximityFar called during transition. Ignoring sensor response.");
return;
}
@@ -392,21 +395,15 @@ public class DozeTriggers implements DozeMachine.Part {
if (state == DozeMachine.State.DOZE_PULSING
|| state == DozeMachine.State.DOZE_PULSING_BRIGHT) {
- if (DEBUG) {
- Log.i(TAG, "Prox changed, ignore touch = " + near);
- }
+ mDozeLog.traceSetIgnoreTouchWhilePulsing(near);
mDozeHost.onIgnoreTouchWhilePulsing(near);
}
if (far && (paused || pausing)) {
- if (DEBUG) {
- Log.i(TAG, "Prox FAR, unpausing AOD");
- }
+ mDozeLog.d("Prox FAR, unpausing AOD");
mMachine.requestState(DozeMachine.State.DOZE_AOD);
} else if (near && aod) {
- if (DEBUG) {
- Log.i(TAG, "Prox NEAR, pausing AOD");
- }
+ mDozeLog.d("Prox NEAR, starting pausing AOD countdown");
mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSING);
}
}
@@ -551,12 +548,13 @@ public class DozeTriggers implements DozeMachine.Part {
return;
}
- if (!mAllowPulseTriggers || mDozeHost.isPulsePending() || !canPulse(dozeState)) {
+ if (!mAllowPulseTriggers || mDozeHost.isPulsePending()
+ || !canPulse(dozeState, performedProxCheck)) {
if (!mAllowPulseTriggers) {
mDozeLog.tracePulseDropped("requestPulse - !mAllowPulseTriggers");
} else if (mDozeHost.isPulsePending()) {
mDozeLog.tracePulseDropped("requestPulse - pulsePending");
- } else if (!canPulse(dozeState)) {
+ } else if (!canPulse(dozeState, performedProxCheck)) {
mDozeLog.tracePulseDropped("requestPulse - dozeState cannot pulse", dozeState);
}
runIfNotNull(onPulseSuppressedListener);
@@ -574,14 +572,15 @@ public class DozeTriggers implements DozeMachine.Part {
// not in pocket, continue pulsing
final boolean isPulsePending = mDozeHost.isPulsePending();
mDozeHost.setPulsePending(false);
- if (!isPulsePending || mDozeHost.isPulsingBlocked() || !canPulse(dozeState)) {
+ if (!isPulsePending || mDozeHost.isPulsingBlocked()
+ || !canPulse(dozeState, performedProxCheck)) {
if (!isPulsePending) {
mDozeLog.tracePulseDropped("continuePulseRequest - pulse no longer"
+ " pending, pulse was cancelled before it could start"
+ " transitioning to pulsing state.");
} else if (mDozeHost.isPulsingBlocked()) {
mDozeLog.tracePulseDropped("continuePulseRequest - pulsingBlocked");
- } else if (!canPulse(dozeState)) {
+ } else if (!canPulse(dozeState, performedProxCheck)) {
mDozeLog.tracePulseDropped("continuePulseRequest"
+ " - doze state cannot pulse", dozeState);
}
@@ -598,10 +597,13 @@ public class DozeTriggers implements DozeMachine.Part {
.ifPresent(uiEventEnum -> mUiEventLogger.log(uiEventEnum, getKeyguardSessionId()));
}
- private boolean canPulse(DozeMachine.State dozeState) {
+ private boolean canPulse(DozeMachine.State dozeState, boolean pulsePerformedProximityCheck) {
+ final boolean dozePausedOrPausing = dozeState == State.DOZE_AOD_PAUSED
+ || dozeState == State.DOZE_AOD_PAUSING;
return dozeState == DozeMachine.State.DOZE
|| dozeState == DozeMachine.State.DOZE_AOD
- || dozeState == DozeMachine.State.DOZE_AOD_DOCKED;
+ || dozeState == DozeMachine.State.DOZE_AOD_DOCKED
+ || (dozePausedOrPausing && pulsePerformedProximityCheck);
}
@Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
new file mode 100644
index 000000000000..83253563e969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.dreams
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import javax.inject.Inject
+
+/**
+ * {@link DreamOverlayLifecycleOwner} is a concrete implementation of {@link LifecycleOwner}, which
+ * provides access to an associated {@link LifecycleRegistry}.
+ */
+class DreamOverlayLifecycleOwner @Inject constructor() : LifecycleOwner {
+ val registry: LifecycleRegistry = LifecycleRegistry(this)
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
index d145f5c14917..87c5f51ce13a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
@@ -16,6 +16,8 @@
package com.android.systemui.dreams;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT;
+
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -35,6 +37,7 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.qualifiers.Main;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be
@@ -98,12 +101,13 @@ public class DreamOverlayRegistrant implements CoreStartable {
}
@Inject
- public DreamOverlayRegistrant(Context context, @Main Resources resources) {
+ public DreamOverlayRegistrant(Context context, @Main Resources resources,
+ @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent) {
mContext = context;
mResources = resources;
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
- mOverlayServiceComponent = new ComponentName(mContext, DreamOverlayService.class);
+ mOverlayServiceComponent = dreamOverlayServiceComponent;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index e76d5b30d3e6..8fdcb0df6900 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -30,6 +30,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.ViewModelStore;
@@ -41,6 +42,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.dreams.complication.dagger.ComplicationComponent;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
@@ -80,8 +82,11 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
// True if the service has been destroyed.
private boolean mDestroyed = false;
+ private final ComplicationComponent mComplicationComponent;
+
private final DreamOverlayComponent mDreamOverlayComponent;
+ private final DreamOverlayLifecycleOwner mLifecycleOwner;
private final LifecycleRegistry mLifecycleRegistry;
private DreamOverlayTouchMonitor mDreamOverlayTouchMonitor;
@@ -127,7 +132,9 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
public DreamOverlayService(
Context context,
@Main Executor executor,
+ DreamOverlayLifecycleOwner lifecycleOwner,
WindowManager windowManager,
+ ComplicationComponent.Factory complicationComponentFactory,
DreamOverlayComponent.Factory dreamOverlayComponentFactory,
DreamOverlayStateController stateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -146,8 +153,12 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
final ViewModelStore viewModelStore = new ViewModelStore();
final Complication.Host host =
() -> mExecutor.execute(DreamOverlayService.this::requestExit);
- mDreamOverlayComponent = dreamOverlayComponentFactory.create(viewModelStore, host);
- mLifecycleRegistry = mDreamOverlayComponent.getLifecycleRegistry();
+
+ mComplicationComponent = complicationComponentFactory.create();
+ mDreamOverlayComponent =
+ dreamOverlayComponentFactory.create(lifecycleOwner, viewModelStore, host, null);
+ mLifecycleOwner = lifecycleOwner;
+ mLifecycleRegistry = mLifecycleOwner.getRegistry();
mExecutor.execute(() -> setCurrentStateLocked(Lifecycle.State.CREATED));
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index 5f942b6fb834..ccfdd0966e98 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -16,6 +16,8 @@
package com.android.systemui.dreams;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_ENABLED;
+
import android.service.dreams.DreamService;
import android.util.Log;
@@ -37,6 +39,7 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* {@link DreamOverlayStateController} is the source of truth for Dream overlay configurations and
@@ -83,6 +86,7 @@ public class DreamOverlayStateController implements
}
private final Executor mExecutor;
+ private final boolean mOverlayEnabled;
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
@Complication.ComplicationType
@@ -94,14 +98,27 @@ public class DreamOverlayStateController implements
@VisibleForTesting
@Inject
- public DreamOverlayStateController(@Main Executor executor) {
+ public DreamOverlayStateController(@Main Executor executor,
+ @Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled) {
mExecutor = executor;
+ mOverlayEnabled = overlayEnabled;
+ if (DEBUG) {
+ Log.d(TAG, "Dream overlay enabled:" + mOverlayEnabled);
+ }
}
/**
* Adds a complication to be included on the dream overlay.
*/
public void addComplication(Complication complication) {
+ if (!mOverlayEnabled) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "Ignoring adding complication due to overlay disabled:" + complication);
+ }
+ return;
+ }
+
mExecutor.execute(() -> {
if (mComplications.add(complication)) {
if (DEBUG) {
@@ -116,6 +133,14 @@ public class DreamOverlayStateController implements
* Removes a complication from inclusion on the dream overlay.
*/
public void removeComplication(Complication complication) {
+ if (!mOverlayEnabled) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "Ignoring removing complication due to overlay disabled:" + complication);
+ }
+ return;
+ }
+
mExecutor.execute(() -> {
if (mComplications.remove(complication)) {
if (DEBUG) {
@@ -193,7 +218,7 @@ public class DreamOverlayStateController implements
* @return {@code true} if overlay is active, {@code false} otherwise.
*/
public boolean isOverlayActive() {
- return containsState(STATE_DREAM_OVERLAY_ACTIVE);
+ return mOverlayEnabled && containsState(STATE_DREAM_OVERLAY_ACTIVE);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
index 100ccc35e638..a2e11b21ea59 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
@@ -138,19 +138,27 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
final ComplicationId id = complication.getId();
final Complication.ViewHolder viewHolder = complication.getComplication()
.createView(complication);
+
+ final View view = viewHolder.getView();
+
+ if (view == null) {
+ Log.e(TAG, "invalid complication view. null view supplied by ViewHolder");
+ return;
+ }
+
// Complications to be added before dream entry animations are finished are set
// to invisible and are animated in.
if (!mEntryAnimationsFinished) {
- viewHolder.getView().setVisibility(View.INVISIBLE);
+ view.setVisibility(View.INVISIBLE);
}
mComplications.put(id, viewHolder);
- if (viewHolder.getView().getParent() != null) {
+ if (view.getParent() != null) {
Log.e(TAG, "View for complication "
+ complication.getComplication().getClass()
+ " already has a parent. Make sure not to reuse complication "
+ "views!");
}
- mLayoutEngine.addComplication(id, viewHolder.getView(),
+ mLayoutEngine.addComplication(id, view,
viewHolder.getLayoutParams(), viewHolder.getCategory());
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt
new file mode 100644
index 000000000000..89497098f8ae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt
@@ -0,0 +1,12 @@
+package com.android.systemui.dreams.complication.dagger
+
+import dagger.Subcomponent
+
+@Subcomponent
+interface ComplicationComponent {
+ /** Factory for generating [ComplicationComponent]. */
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(): ComplicationComponent
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index 101f4a450071..8770cd16ca27 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -16,7 +16,9 @@
package com.android.systemui.dreams.dagger;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import com.android.dream.lowlight.dagger.LowLightDreamModule;
@@ -24,14 +26,17 @@ import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
+import com.android.systemui.dreams.DreamOverlayService;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
+import com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent;
+
+import dagger.Module;
+import dagger.Provides;
import java.util.Optional;
import javax.inject.Named;
-import dagger.Module;
-import dagger.Provides;
/**
* Dagger Module providing Dream-related functionality.
@@ -41,14 +46,40 @@ import dagger.Provides;
LowLightDreamModule.class,
},
subcomponents = {
+ ComplicationComponent.class,
DreamOverlayComponent.class,
})
public interface DreamModule {
String DREAM_ONLY_ENABLED_FOR_DOCK_USER = "dream_only_enabled_for_dock_user";
+ String DREAM_OVERLAY_SERVICE_COMPONENT = "dream_overlay_service_component";
+ String DREAM_OVERLAY_ENABLED = "dream_overlay_enabled";
String DREAM_SUPPORTED = "dream_supported";
/**
+ * Provides the dream component
+ */
+ @Provides
+ @Named(DREAM_OVERLAY_SERVICE_COMPONENT)
+ static ComponentName providesDreamOverlayService(Context context) {
+ return new ComponentName(context, DreamOverlayService.class);
+ }
+
+ /**
+ * Provides whether dream overlay is enabled.
+ */
+ @Provides
+ @Named(DREAM_OVERLAY_ENABLED)
+ static Boolean providesDreamOverlayEnabled(PackageManager packageManager,
+ @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName component) {
+ try {
+ return packageManager.getServiceInfo(component, PackageManager.GET_META_DATA).enabled;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
* Provides an instance of the dream backend.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
index f927ba64a92b..584829074cf4 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
@@ -16,26 +16,32 @@
package com.android.systemui.dreams.dagger;
+import static com.android.systemui.dreams.dagger.DreamOverlayModule.DREAM_TOUCH_HANDLERS;
+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import android.annotation.Nullable;
+
import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.ViewModelStore;
import com.android.systemui.dreams.DreamOverlayContainerViewController;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.complication.dagger.ComplicationModule;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
+import com.android.systemui.dreams.touch.DreamTouchHandler;
import com.android.systemui.dreams.touch.dagger.DreamTouchModule;
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
+import java.util.Set;
+import javax.inject.Named;
import javax.inject.Scope;
-import dagger.BindsInstance;
-import dagger.Subcomponent;
-
/**
* Dagger subcomponent for {@link DreamOverlayModule}.
*/
@@ -49,8 +55,12 @@ public interface DreamOverlayComponent {
/** Simple factory for {@link DreamOverlayComponent}. */
@Subcomponent.Factory
interface Factory {
- DreamOverlayComponent create(@BindsInstance ViewModelStore store,
- @BindsInstance Complication.Host host);
+ DreamOverlayComponent create(
+ @BindsInstance LifecycleOwner lifecycleOwner,
+ @BindsInstance ViewModelStore store,
+ @BindsInstance Complication.Host host,
+ @BindsInstance @Named(DREAM_TOUCH_HANDLERS) @Nullable
+ Set<DreamTouchHandler> dreamTouchHandlers);
}
/** Scope annotation for singleton items within the {@link DreamOverlayComponent}. */
@@ -62,12 +72,6 @@ public interface DreamOverlayComponent {
/** Builds a {@link DreamOverlayContainerViewController}. */
DreamOverlayContainerViewController getDreamOverlayContainerViewController();
- /** Builds a {@link androidx.lifecycle.LifecycleRegistry} */
- LifecycleRegistry getLifecycleRegistry();
-
- /** Builds a {@link androidx.lifecycle.LifecycleOwner} */
- LifecycleOwner getLifecycleOwner();
-
/** Builds a {@link DreamOverlayTouchMonitor} */
DreamOverlayTouchMonitor getDreamOverlayTouchMonitor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index ed0e1d97e40a..67e25713987f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -16,32 +16,40 @@
package com.android.systemui.dreams.dagger;
+import android.annotation.Nullable;
import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
import com.android.internal.util.Preconditions;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayContainerView;
import com.android.systemui.dreams.DreamOverlayStatusBarView;
+import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.dreams.dreamcomplication.HideComplicationTouchHandler;
+import com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent;
+import com.android.systemui.dreams.touch.DreamTouchHandler;
import com.android.systemui.touch.TouchInsetManager;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+import dagger.multibindings.IntoSet;
+
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.Executor;
import javax.inject.Named;
-import dagger.Lazy;
-import dagger.Module;
-import dagger.Provides;
-
/** Dagger module for {@link DreamOverlayComponent}. */
@Module
public abstract class DreamOverlayModule {
+ public static final String DREAM_TOUCH_HANDLERS = "dream_touch_handlers";
public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
public static final String MAX_BURN_IN_OFFSET = "max_burn_in_offset";
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
@@ -246,19 +254,28 @@ public abstract class DreamOverlayModule {
@Provides
@DreamOverlayComponent.DreamOverlayScope
- static LifecycleOwner providesLifecycleOwner(Lazy<LifecycleRegistry> lifecycleRegistryLazy) {
- return () -> lifecycleRegistryLazy.get();
+ static Lifecycle providesLifecycle(LifecycleOwner lifecycleOwner) {
+ return lifecycleOwner.getLifecycle();
}
@Provides
- @DreamOverlayComponent.DreamOverlayScope
- static LifecycleRegistry providesLifecycleRegistry(LifecycleOwner lifecycleOwner) {
- return new LifecycleRegistry(lifecycleOwner);
+ @ElementsIntoSet
+ static Set<DreamTouchHandler> providesDreamTouchHandlers(
+ @Named(DREAM_TOUCH_HANDLERS) @Nullable Set<DreamTouchHandler> touchHandlers) {
+ return touchHandlers != null ? touchHandlers : new HashSet<>();
}
+ /**
+ * Provides {@link HideComplicationTouchHandler} for inclusion in touch handling over the dream.
+ */
@Provides
- @DreamOverlayComponent.DreamOverlayScope
- static Lifecycle providesLifecycle(LifecycleOwner lifecycleOwner) {
- return lifecycleOwner.getLifecycle();
+ @IntoSet
+ public static DreamTouchHandler providesHideComplicationTouchHandler(
+ ComplicationComponent.Factory componentFactory,
+ Complication.VisibilityController visibilityController,
+ TouchInsetManager touchInsetManager) {
+ ComplicationComponent component =
+ componentFactory.create(visibilityController, touchInsetManager);
+ return component.getHideComplicationTouchHandler();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandler.java
index e276e0c65b1e..3a4578b6f744 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandler.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.dreams.touch;
+package com.android.systemui.dreams.dreamcomplication;
-import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DELAY;
-import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_RESTORE_TIMEOUT;
+import static com.android.systemui.dreams.dreamcomplication.dagger.ComplicationModule.COMPLICATIONS_FADE_OUT_DELAY;
+import static com.android.systemui.dreams.dreamcomplication.dagger.ComplicationModule.COMPLICATIONS_RESTORE_TIMEOUT;
import android.util.Log;
import android.view.MotionEvent;
@@ -28,6 +28,8 @@ import androidx.annotation.Nullable;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
+import com.android.systemui.dreams.touch.DreamTouchHandler;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationComponent.kt b/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationComponent.kt
new file mode 100644
index 000000000000..f2fb48d6240d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationComponent.kt
@@ -0,0 +1,21 @@
+package com.android.systemui.dreams.dreamcomplication.dagger
+
+import com.android.systemui.dreams.complication.Complication
+import com.android.systemui.dreams.dreamcomplication.HideComplicationTouchHandler
+import com.android.systemui.touch.TouchInsetManager
+import dagger.BindsInstance
+import dagger.Subcomponent
+
+@Subcomponent(modules = [ComplicationModule::class])
+interface ComplicationComponent {
+ /** Factory for generating [ComplicationComponent]. */
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance visibilityController: Complication.VisibilityController,
+ @BindsInstance touchInsetManager: TouchInsetManager
+ ): ComplicationComponent
+ }
+
+ fun getHideComplicationTouchHandler(): HideComplicationTouchHandler
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationModule.kt b/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationModule.kt
new file mode 100644
index 000000000000..ef75ce173e94
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationModule.kt
@@ -0,0 +1,28 @@
+package com.android.systemui.dreams.dreamcomplication.dagger
+
+import android.content.res.Resources
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Main
+import dagger.Module
+import dagger.Provides
+import javax.inject.Named
+
+@Module
+object ComplicationModule {
+ const val COMPLICATIONS_RESTORE_TIMEOUT = "complication_restore_timeout"
+ const val COMPLICATIONS_FADE_OUT_DELAY = "complication_fade_out_delay"
+
+ /** Provides the delay to wait for before fading out complications. */
+ @Provides
+ @Named(COMPLICATIONS_FADE_OUT_DELAY)
+ fun providesComplicationsFadeOutDelay(@Main resources: Resources): Int {
+ return resources.getInteger(R.integer.complicationFadeOutDelayMs)
+ }
+
+ /** Provides the timeout for restoring complication visibility. */
+ @Provides
+ @Named(COMPLICATIONS_RESTORE_TIMEOUT)
+ fun providesComplicationsRestoreTimeout(@Main resources: Resources): Int {
+ return resources.getInteger(R.integer.complicationRestoreMs)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java
index 7338ecba8cf3..dad0004613f6 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java
@@ -23,7 +23,6 @@ import dagger.Module;
*/
@Module(includes = {
BouncerSwipeModule.class,
- HideComplicationModule.class,
}, subcomponents = {
InputSessionComponent.class,
})
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java
deleted file mode 100644
index 3800ff75aed0..000000000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java
+++ /dev/null
@@ -1,40 +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.systemui.dreams.touch.dagger;
-
-import com.android.systemui.dreams.touch.DreamTouchHandler;
-import com.android.systemui.dreams.touch.HideComplicationTouchHandler;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-/**
- * Module for {@link HideComplicationTouchHandler}.
- */
-@Module
-public class HideComplicationModule {
- /**
- * Provides {@link HideComplicationTouchHandler} for inclusion in touch handling over the dream.
- */
- @Provides
- @IntoSet
- public static DreamTouchHandler providesHideComplicationTouchHandler(
- HideComplicationTouchHandler touchHandler) {
- return touchHandler;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index ff3714f03f86..4a046e123001 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -83,7 +83,7 @@ object Flags {
val STABILITY_INDEX_FIX = releasedFlag(114, "stability_index_fix")
// TODO(b/259559750): Tracking Bug
- val SEMI_STABLE_SORT = unreleasedFlag(115, "semi_stable_sort", teamfood = true)
+ val SEMI_STABLE_SORT = releasedFlag(115, "semi_stable_sort")
@JvmField
val USE_ROUNDNESS_SOURCETYPES = unreleasedFlag(116, "use_roundness_sourcetype", teamfood = true)
@@ -94,8 +94,7 @@ object Flags {
unreleasedFlag(259217907, "notification_group_dismissal_animation", teamfood = true)
// TODO(b/257506350): Tracking Bug
- @JvmField
- val FSI_CHROME = unreleasedFlag(117, "fsi_chrome")
+ @JvmField val FSI_CHROME = unreleasedFlag(117, "fsi_chrome")
@JvmField
val SIMPLIFIED_APPEAR_FRACTION =
@@ -173,7 +172,7 @@ object Flags {
* new KeyguardTransitionRepository.
*/
@JvmField
- val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = true)
+ val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = false)
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@@ -251,11 +250,7 @@ object Flags {
// 801 - region sampling
// TODO(b/254512848): Tracking Bug
- val REGION_SAMPLING = unreleasedFlag(801, "region_sampling")
-
- // 802 - wallpaper rendering
- // TODO(b/254512923): Tracking Bug
- @JvmField val USE_CANVAS_RENDERER = unreleasedFlag(802, "use_canvas_renderer")
+ val REGION_SAMPLING = unreleasedFlag(801, "region_sampling", teamfood = true)
// 803 - screen contents translation
// TODO(b/254513187): Tracking Bug
@@ -288,7 +283,11 @@ object Flags {
// TODO(b/254513168): Tracking Bug
@JvmField val UMO_SURFACE_RIPPLE = unreleasedFlag(907, "umo_surface_ripple")
- @JvmField val MEDIA_FALSING_PENALTY = unreleasedFlag(908, "media_falsing_media")
+ @JvmField
+ val MEDIA_FALSING_PENALTY = unreleasedFlag(908, "media_falsing_media", teamfood = true)
+
+ // TODO(b/261734857): Tracking Bug
+ @JvmField val UMO_TURBULENCE_NOISE = unreleasedFlag(909, "umo_turbulence_noise")
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
@@ -419,6 +418,10 @@ object Flags {
// 2000 - device controls
@Keep @JvmField val USE_APP_PANELS = unreleasedFlag(2000, "use_app_panels", teamfood = true)
+ @JvmField
+ val APP_PANELS_ALL_APPS_ALLOWED =
+ unreleasedFlag(2001, "app_panels_all_apps_allowed", teamfood = true)
+
// 2100 - Falsing Manager
@JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps")
@@ -430,6 +433,9 @@ object Flags {
// 2300 - stylus
@JvmField val TRACK_STYLUS_EVER_USED = unreleasedFlag(2300, "track_stylus_ever_used")
+ @JvmField val ENABLE_STYLUS_CHARGING_UI = unreleasedFlag(2301, "enable_stylus_charging_ui")
+ @JvmField
+ val ENABLE_USI_BATTERY_NOTIFICATIONS = unreleasedFlag(2302, "enable_usi_battery_notifications")
// 2400 - performance tools and debugging info
// TODO(b/238923086): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index db2cd91374e5..c3e163fbeecc 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -733,7 +733,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
@VisibleForTesting
boolean shouldDisplayBugReport(UserInfo currentUser) {
return mGlobalSettings.getInt(Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0
- && (currentUser == null || currentUser.isPrimary());
+ && (currentUser == null || currentUser.isAdmin());
}
@Override
@@ -1058,8 +1058,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
@Override
public boolean showBeforeProvisioning() {
- return Build.isDebuggable() && mGlobalSettings.getInt(
- Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0;
+ return Build.isDebuggable() && mGlobalSettings.getIntForUser(
+ Settings.Global.BUGREPORT_IN_POWER_MENU, 0, getCurrentUser().id) != 0
+ && getCurrentUser().isAdmin();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 36c939d1156e..d6418d0829a3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1614,7 +1614,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// TODO: Rename all screen off/on references to interactive/sleeping
synchronized (this) {
mDeviceInteractive = true;
- if (mPendingLock && !cameraGestureTriggered) {
+ if (mPendingLock && !cameraGestureTriggered && !mWakeAndUnlocking) {
doKeyguardLocked(null);
}
mAnimatingScreenOff = false;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 783f752cbd20..90f3c7d88c8f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -16,23 +16,36 @@
package com.android.systemui.keyguard.data.repository
-import com.android.keyguard.KeyguardUpdateMonitor
+import android.os.Build
import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
+import com.android.systemui.log.dagger.BouncerLog
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.phone.KeyguardBouncer
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
-/** Encapsulates app state for the lock screen primary and alternate bouncer. */
+/**
+ * Encapsulates app state for the lock screen primary and alternate bouncer.
+ *
+ * Make sure to add newly added flows to the logger.
+ */
@SysUISingleton
class KeyguardBouncerRepository
@Inject
constructor(
private val viewMediatorCallback: ViewMediatorCallback,
- keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ @Application private val applicationScope: CoroutineScope,
+ @BouncerLog private val buffer: TableLogBuffer,
) {
/** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
private val _primaryBouncerVisible = MutableStateFlow(false)
@@ -77,6 +90,10 @@ constructor(
val bouncerErrorMessage: CharSequence?
get() = viewMediatorCallback.consumeCustomMessage()
+ init {
+ setUpLogging()
+ }
+
fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed
}
@@ -132,4 +149,57 @@ constructor(
fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean) {
_onScreenTurnedOff.value = onScreenTurnedOff
}
+
+ /** Sets up logs for state flows. */
+ private fun setUpLogging() {
+ if (!Build.IS_DEBUGGABLE) {
+ return
+ }
+
+ primaryBouncerVisible
+ .logDiffsForTable(buffer, "", "PrimaryBouncerVisible", false)
+ .launchIn(applicationScope)
+ primaryBouncerShow
+ .map { it != null }
+ .logDiffsForTable(buffer, "", "PrimaryBouncerShow", false)
+ .launchIn(applicationScope)
+ primaryBouncerShowingSoon
+ .logDiffsForTable(buffer, "", "PrimaryBouncerShowingSoon", false)
+ .launchIn(applicationScope)
+ primaryBouncerHide
+ .logDiffsForTable(buffer, "", "PrimaryBouncerHide", false)
+ .launchIn(applicationScope)
+ primaryBouncerStartingToHide
+ .logDiffsForTable(buffer, "", "PrimaryBouncerStartingToHide", false)
+ .launchIn(applicationScope)
+ primaryBouncerStartingDisappearAnimation
+ .map { it != null }
+ .logDiffsForTable(buffer, "", "PrimaryBouncerStartingDisappearAnimation", false)
+ .launchIn(applicationScope)
+ primaryBouncerScrimmed
+ .logDiffsForTable(buffer, "", "PrimaryBouncerScrimmed", false)
+ .launchIn(applicationScope)
+ panelExpansionAmount
+ .map { (it * 1000).toInt() }
+ .logDiffsForTable(buffer, "", "PanelExpansionAmountMillis", -1)
+ .launchIn(applicationScope)
+ keyguardPosition
+ .map { it.toInt() }
+ .logDiffsForTable(buffer, "", "KeyguardPosition", -1)
+ .launchIn(applicationScope)
+ onScreenTurnedOff
+ .logDiffsForTable(buffer, "", "OnScreenTurnedOff", false)
+ .launchIn(applicationScope)
+ isBackButtonEnabled
+ .filterNotNull()
+ .logDiffsForTable(buffer, "", "IsBackButtonEnabled", false)
+ .launchIn(applicationScope)
+ showMessage
+ .map { it?.message }
+ .logDiffsForTable(buffer, "", "ShowMessage", null)
+ .launchIn(applicationScope)
+ resourceUpdateRequests
+ .logDiffsForTable(buffer, "", "ResourceUpdateRequests", false)
+ .launchIn(applicationScope)
+ }
}
diff --git a/services/permission/java/com/android/server/permission/access/external/CompatibilityPermissionInfo.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/BouncerLog.kt
index aadd8baedc81..2251a7b243aa 100644
--- a/services/permission/java/com/android/server/permission/access/external/CompatibilityPermissionInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BouncerLog.kt
@@ -14,16 +14,12 @@
* limitations under the License.
*/
-package com.android.server.permission.access.external
+package com.android.systemui.log.dagger
-class CompatibilityPermissionInfo {
- companion object {
- val COMPAT_PERMS = arrayOf(CompatibilityPermissionInfo())
- }
+import java.lang.annotation.Documented
+import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
+import javax.inject.Qualifier
- val name: String
- get() = throw NotImplementedError()
-
- val sdkVersion: Int
- get() = throw NotImplementedError()
-}
+/** Logger for the primary and alternative bouncers. */
+@Qualifier @Documented @Retention(RetentionPolicy.RUNTIME) annotation class BouncerLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index f5a97ce67098..a7d60a125bee 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -23,6 +23,8 @@ import android.os.Looper;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.log.LogBufferFactory;
+import com.android.systemui.log.table.TableLogBuffer;
+import com.android.systemui.log.table.TableLogBufferFactory;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogcatEchoTracker;
import com.android.systemui.plugins.log.LogcatEchoTrackerDebug;
@@ -345,6 +347,14 @@ public class LogModule {
return factory.create("BluetoothLog", 50);
}
+ /** Provides a logging buffer for the primary bouncer. */
+ @Provides
+ @SysUISingleton
+ @BouncerLog
+ public static TableLogBuffer provideBouncerLogBuffer(TableLogBufferFactory factory) {
+ return factory.create("BouncerLog", 250);
+ }
+
/**
* Provides a {@link LogBuffer} for Udfps logs.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
index bb04b6b41a33..348d941d22cf 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
@@ -100,3 +100,46 @@ fun Flow<Boolean>.logDiffsForTable(
newVal
}
}
+/**
+ * Each time the Int flow is updated with a new value that's different from the previous value, logs
+ * the new value to the given [tableLogBuffer].
+ */
+fun Flow<Int>.logDiffsForTable(
+ tableLogBuffer: TableLogBuffer,
+ columnPrefix: String,
+ columnName: String,
+ initialValue: Int,
+): Flow<Int> {
+ val initialValueFun = {
+ tableLogBuffer.logChange(columnPrefix, columnName, initialValue)
+ initialValue
+ }
+ return this.pairwiseBy(initialValueFun) { prevVal, newVal: Int ->
+ if (prevVal != newVal) {
+ tableLogBuffer.logChange(columnPrefix, columnName, newVal)
+ }
+ newVal
+ }
+}
+
+/**
+ * Each time the String? flow is updated with a new value that's different from the previous value,
+ * logs the new value to the given [tableLogBuffer].
+ */
+fun Flow<String?>.logDiffsForTable(
+ tableLogBuffer: TableLogBuffer,
+ columnPrefix: String,
+ columnName: String,
+ initialValue: String?,
+): Flow<String?> {
+ val initialValueFun = {
+ tableLogBuffer.logChange(columnPrefix, columnName, initialValue)
+ initialValue
+ }
+ return this.pairwiseBy(initialValueFun) { prevVal, newVal: String? ->
+ if (prevVal != newVal) {
+ tableLogBuffer.logChange(columnPrefix, columnName, newVal)
+ }
+ newVal
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 9d0b833d26cc..2c299d67022d 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -127,11 +127,21 @@ class TableLogBuffer(
rowInitializer(row)
}
+ /** Logs a String? change. */
+ fun logChange(prefix: String, columnName: String, value: String?) {
+ logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
+ }
+
/** Logs a boolean change. */
fun logChange(prefix: String, columnName: String, value: Boolean) {
logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
}
+ /** Logs a Int change. */
+ fun logChange(prefix: String, columnName: String, value: Int) {
+ logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
+ }
+
// Keep these individual [logChange] methods private (don't let clients give us their own
// timestamps.)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index df8fb9149f30..db7a145e2ade 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -224,6 +224,8 @@ public class MediaControlPanel {
private TurbulenceNoiseController mTurbulenceNoiseController;
private FeatureFlags mFeatureFlags;
private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig = null;
+ @VisibleForTesting
+ MultiRippleController.Companion.RipplesFinishedListener mRipplesFinishedListener = null;
/**
* Initialize a new control panel
@@ -404,15 +406,17 @@ public class MediaControlPanel {
MultiRippleView multiRippleView = vh.getMultiRippleView();
mMultiRippleController = new MultiRippleController(multiRippleView);
mTurbulenceNoiseController = new TurbulenceNoiseController(vh.getTurbulenceNoiseView());
- multiRippleView.addRipplesFinishedListener(
- () -> {
- if (mTurbulenceNoiseAnimationConfig == null) {
- mTurbulenceNoiseAnimationConfig = createLingeringNoiseAnimation();
- }
- // Color will be correctly updated in ColorSchemeTransition.
- mTurbulenceNoiseController.play(mTurbulenceNoiseAnimationConfig);
+ if (mFeatureFlags.isEnabled(Flags.UMO_TURBULENCE_NOISE)) {
+ mRipplesFinishedListener = () -> {
+ if (mTurbulenceNoiseAnimationConfig == null) {
+ mTurbulenceNoiseAnimationConfig = createLingeringNoiseAnimation();
}
- );
+ // Color will be correctly updated in ColorSchemeTransition.
+ mTurbulenceNoiseController.play(mTurbulenceNoiseAnimationConfig);
+ };
+ mMultiRippleController.addRipplesFinishedListener(mRipplesFinishedListener);
+ }
+
mColorSchemeTransition = new ColorSchemeTransition(
mContext, mMediaViewHolder, mMultiRippleController, mTurbulenceNoiseController);
mMetadataAnimationHandler = new MetadataAnimationHandler(exit, enter);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
new file mode 100644
index 000000000000..875a01087908
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dialog;
+
+import androidx.annotation.IntDef;
+
+import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Optional;
+
+/**
+ * MediaItem represents an item in OutputSwitcher list (could be a MediaDevice, group divider or
+ * connect new device item).
+ */
+public class MediaItem {
+ private final Optional<MediaDevice> mMediaDeviceOptional;
+ private final String mTitle;
+ @MediaItemType
+ private final int mMediaItemType;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ MediaItemType.TYPE_DEVICE,
+ MediaItemType.TYPE_GROUP_DIVIDER,
+ MediaItemType.TYPE_PAIR_NEW_DEVICE})
+ public @interface MediaItemType {
+ int TYPE_DEVICE = 0;
+ int TYPE_GROUP_DIVIDER = 1;
+ int TYPE_PAIR_NEW_DEVICE = 2;
+ }
+
+ public MediaItem() {
+ this.mMediaDeviceOptional = Optional.empty();
+ this.mTitle = null;
+ this.mMediaItemType = MediaItemType.TYPE_PAIR_NEW_DEVICE;
+ }
+
+ public MediaItem(String title, int mediaItemType) {
+ this.mMediaDeviceOptional = Optional.empty();
+ this.mTitle = title;
+ this.mMediaItemType = mediaItemType;
+ }
+
+ public MediaItem(MediaDevice mediaDevice) {
+ this.mMediaDeviceOptional = Optional.of(mediaDevice);
+ this.mTitle = mediaDevice.getName();
+ this.mMediaItemType = MediaItemType.TYPE_DEVICE;
+ }
+
+ public Optional<MediaDevice> getMediaDevice() {
+ return mMediaDeviceOptional;
+ }
+
+ /**
+ * Get layout id based on media item Type.
+ */
+ public static int getMediaLayoutId(int mediaItemType) {
+ switch (mediaItemType) {
+ case MediaItemType.TYPE_DEVICE:
+ case MediaItemType.TYPE_PAIR_NEW_DEVICE:
+ return R.layout.media_output_list_item_advanced;
+ case MediaItemType.TYPE_GROUP_DIVIDER:
+ default:
+ return R.layout.media_output_list_group_divider;
+ }
+ }
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public boolean isMutingExpectedDevice() {
+ return mMediaDeviceOptional.isPresent()
+ && mMediaDeviceOptional.get().isMutingExpectedDevice();
+ }
+
+ public int getMediaItemType() {
+ return mMediaItemType;
+ }
+}
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 3dccae03e906..fb47d97ed1d4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -24,9 +24,11 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
+import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.widget.CompoundButtonCompat;
+import androidx.recyclerview.widget.RecyclerView;
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
import com.android.settingslib.media.MediaDevice;
@@ -48,29 +50,68 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
@Override
- public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
super.onCreateViewHolder(viewGroup, viewType);
- return new MediaDeviceViewHolder(mHolderView);
+ if (mController.isAdvancedLayoutSupported()) {
+ switch (viewType) {
+ case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
+ return new MediaGroupDividerViewHolder(mHolderView);
+ case MediaItem.MediaItemType.TYPE_PAIR_NEW_DEVICE:
+ case MediaItem.MediaItemType.TYPE_DEVICE:
+ default:
+ return new MediaDeviceViewHolder(mHolderView);
+ }
+ } else {
+ return new MediaDeviceViewHolder(mHolderView);
+ }
}
@Override
- public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) {
- final int size = mController.getMediaDevices().size();
- if (position == size) {
- viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
- true /* bottomMargin */);
- } else if (position < size) {
- viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
- position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */,
- position);
- } else if (DEBUG) {
- Log.d(TAG, "Incorrect position: " + position);
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ if (mController.isAdvancedLayoutSupported()) {
+ MediaItem currentMediaItem = mController.getMediaItemList().get(position);
+ switch (currentMediaItem.getMediaItemType()) {
+ case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
+ ((MediaGroupDividerViewHolder) viewHolder).onBind(currentMediaItem.getTitle());
+ break;
+ case MediaItem.MediaItemType.TYPE_PAIR_NEW_DEVICE:
+ ((MediaDeviceViewHolder) viewHolder).onBind(CUSTOMIZED_ITEM_PAIR_NEW);
+ break;
+ case MediaItem.MediaItemType.TYPE_DEVICE:
+ ((MediaDeviceViewHolder) viewHolder).onBind(
+ currentMediaItem.getMediaDevice().get(),
+ position);
+ break;
+ default:
+ Log.d(TAG, "Incorrect position: " + position);
+ }
+ } else {
+ final int size = mController.getMediaDevices().size();
+ if (position == size) {
+ ((MediaDeviceViewHolder) viewHolder).onBind(CUSTOMIZED_ITEM_PAIR_NEW);
+ } else if (position < size) {
+ ((MediaDeviceViewHolder) viewHolder).onBind(
+ ((List<MediaDevice>) (mController.getMediaDevices())).get(position),
+ position);
+ } else if (DEBUG) {
+ Log.d(TAG, "Incorrect position: " + position);
+ }
}
}
@Override
public long getItemId(int position) {
+ if (mController.isAdvancedLayoutSupported()) {
+ if (position >= mController.getMediaItemList().size()) {
+ Log.d(TAG, "Incorrect position for item id: " + position);
+ return position;
+ }
+ MediaItem currentMediaItem = mController.getMediaItemList().get(position);
+ return currentMediaItem.getMediaDevice().isPresent()
+ ? currentMediaItem.getMediaDevice().get().getId().hashCode()
+ : position;
+ }
final int size = mController.getMediaDevices().size();
if (position == size) {
return -1;
@@ -84,9 +125,18 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
@Override
+ public int getItemViewType(int position) {
+ return mController.isAdvancedLayoutSupported()
+ ? mController.getMediaItemList().get(position).getMediaItemType()
+ : super.getItemViewType(position);
+ }
+
+ @Override
public int getItemCount() {
// Add extra one for "pair new"
- return mController.getMediaDevices().size() + 1;
+ return mController.isAdvancedLayoutSupported()
+ ? mController.getMediaItemList().size()
+ : mController.getMediaDevices().size() + 1;
}
class MediaDeviceViewHolder extends MediaDeviceBaseViewHolder {
@@ -96,8 +146,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
@Override
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
- super.onBind(device, topMargin, bottomMargin, position);
+ void onBind(MediaDevice device, int position) {
+ super.onBind(device, position);
boolean isMutingExpectedDeviceExist = mController.hasMutingExpectedDevice();
final boolean currentlyConnected = isCurrentlyConnected(device);
boolean isCurrentSeekbarInvisible = mSeekBar.getVisibility() == View.GONE;
@@ -261,7 +311,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
@Override
- void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
+ void onBind(int customizedItem) {
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
mTitleText.setTextColor(mController.getColorItemContent());
mCheckBox.setVisibility(View.GONE);
@@ -318,4 +368,18 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
: R.string.accessibility_cast_name, device.getName()));
}
}
+
+ class MediaGroupDividerViewHolder extends RecyclerView.ViewHolder {
+ final TextView mTitleText;
+
+ MediaGroupDividerViewHolder(@NonNull View itemView) {
+ super(itemView);
+ mTitleText = itemView.requireViewById(R.id.title);
+ }
+
+ void onBind(String groupDividerTitle) {
+ mTitleText.setTextColor(mController.getColorItemContent());
+ mTitleText.setText(groupDividerTitle);
+ }
+ }
}
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 db62e51be7e7..3b1d861d0312 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -58,7 +58,7 @@ import java.util.List;
* Base adapter for media output dialog.
*/
public abstract class MediaOutputBaseAdapter extends
- RecyclerView.Adapter<MediaOutputBaseAdapter.MediaDeviceBaseViewHolder> {
+ RecyclerView.Adapter<RecyclerView.ViewHolder> {
static final int CUSTOMIZED_ITEM_PAIR_NEW = 1;
static final int CUSTOMIZED_ITEM_GROUP = 2;
@@ -80,11 +80,12 @@ public abstract class MediaOutputBaseAdapter extends
}
@Override
- public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
mContext = viewGroup.getContext();
mHolderView = LayoutInflater.from(mContext).inflate(
- mController.isAdvancedLayoutSupported() ? R.layout.media_output_list_item_advanced
+ mController.isAdvancedLayoutSupported() ? MediaItem.getMediaLayoutId(
+ viewType) /*R.layout.media_output_list_item_advanced*/
: R.layout.media_output_list_item, viewGroup, false);
return null;
@@ -175,7 +176,7 @@ public abstract class MediaOutputBaseAdapter extends
initAnimator();
}
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
+ void onBind(MediaDevice device, int position) {
mDeviceId = device.getId();
mCheckBox.setVisibility(View.GONE);
mStatusIcon.setVisibility(View.GONE);
@@ -196,7 +197,7 @@ public abstract class MediaOutputBaseAdapter extends
PorterDuff.Mode.SRC_IN));
}
- abstract void onBind(int customizedItem, boolean topMargin, boolean bottomMargin);
+ abstract void onBind(int customizedItem);
void setSingleLineLayout(CharSequence title) {
setSingleLineLayout(title, false, false, false, false);
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 9b361e3edc57..b43656207821 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -93,6 +93,7 @@ import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -121,6 +122,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>();
+ private final List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>();
private final AudioManager mAudioManager;
private final PowerExemptionManager mPowerExemptionManager;
private final KeyguardManager mKeyGuardManager;
@@ -212,6 +214,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
synchronized (mMediaDevicesLock) {
mCachedMediaDevices.clear();
mMediaDevices.clear();
+ mMediaItemList.clear();
}
mNearbyDeviceInfoMap.clear();
if (mNearbyMediaDevicesManager != null) {
@@ -262,6 +265,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
synchronized (mMediaDevicesLock) {
mCachedMediaDevices.clear();
mMediaDevices.clear();
+ mMediaItemList.clear();
}
if (mNearbyMediaDevicesManager != null) {
mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this);
@@ -287,7 +291,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
public void onSelectedDeviceStateChanged(MediaDevice device,
@LocalMediaManager.MediaDeviceState int state) {
mCallback.onRouteChanged();
- mMetricLogger.logOutputSuccess(device.toString(), new ArrayList<>(mMediaDevices));
+ if (isAdvancedLayoutSupported()) {
+ mMetricLogger.logOutputItemSuccess(device.toString(), new ArrayList<>(mMediaItemList));
+ } else {
+ mMetricLogger.logOutputSuccess(device.toString(), new ArrayList<>(mMediaDevices));
+ }
}
@Override
@@ -298,7 +306,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
@Override
public void onRequestFailed(int reason) {
mCallback.onRouteChanged();
- mMetricLogger.logOutputFailure(new ArrayList<>(mMediaDevices), reason);
+ if (isAdvancedLayoutSupported()) {
+ mMetricLogger.logOutputItemFailure(new ArrayList<>(mMediaItemList), reason);
+ } else {
+ mMetricLogger.logOutputFailure(new ArrayList<>(mMediaDevices), reason);
+ }
}
/**
@@ -318,6 +330,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
try {
synchronized (mMediaDevicesLock) {
mMediaDevices.removeIf(MediaDevice::isMutingExpectedDevice);
+ mMediaItemList.removeIf((MediaItem::isMutingExpectedDevice));
}
mAudioManager.cancelMuteAwaitConnection(mAudioManager.getMutingExpectedDevice());
} catch (Exception e) {
@@ -547,6 +560,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
private void buildMediaDevices(List<MediaDevice> devices) {
+ if (isAdvancedLayoutSupported()) {
+ buildMediaItems(devices);
+ } else {
+ buildDefaultMediaDevices(devices);
+ }
+ }
+
+ private void buildDefaultMediaDevices(List<MediaDevice> devices) {
synchronized (mMediaDevicesLock) {
attachRangeInfo(devices);
Collections.sort(devices, Comparator.naturalOrder());
@@ -603,6 +624,81 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
}
+ private void buildMediaItems(List<MediaDevice> devices) {
+ synchronized (mMediaDevicesLock) {
+ //TODO(b/257851968): do the organization only when there's no suggested sorted order
+ // we get from application
+ attachRangeInfo(devices);
+ Collections.sort(devices, Comparator.naturalOrder());
+ // For the first time building list, to make sure the top device is the connected
+ // device.
+ if (mMediaItemList.isEmpty()) {
+ boolean needToHandleMutingExpectedDevice =
+ hasMutingExpectedDevice() && !isCurrentConnectedDeviceRemote();
+ final MediaDevice connectedMediaDevice =
+ needToHandleMutingExpectedDevice ? null
+ : getCurrentConnectedMediaDevice();
+ if (connectedMediaDevice == null) {
+ if (DEBUG) {
+ Log.d(TAG, "No connected media device or muting expected device exist.");
+ }
+ if (needToHandleMutingExpectedDevice) {
+ for (MediaDevice device : devices) {
+ if (device.isMutingExpectedDevice()) {
+ mMediaItemList.add(0, new MediaItem(device));
+ } else {
+ mMediaItemList.add(new MediaItem(device));
+ }
+ }
+ } else {
+ mMediaItemList.addAll(
+ devices.stream().map(MediaItem::new).collect(Collectors.toList()));
+ }
+
+ categorizeMediaItems();
+ return;
+ }
+ // selected device exist
+ for (MediaDevice device : devices) {
+ if (TextUtils.equals(device.getId(), connectedMediaDevice.getId())) {
+ mMediaItemList.add(0, new MediaItem(device));
+ } else {
+ mMediaItemList.add(new MediaItem(device));
+ }
+ }
+ categorizeMediaItems();
+ return;
+ }
+ // To keep the same list order
+ final List<MediaDevice> targetMediaDevices = new ArrayList<>();
+ for (MediaItem originalMediaItem : mMediaItemList) {
+ for (MediaDevice newDevice : devices) {
+ if (originalMediaItem.getMediaDevice().isPresent()
+ && TextUtils.equals(originalMediaItem.getMediaDevice().get().getId(),
+ newDevice.getId())) {
+ targetMediaDevices.add(newDevice);
+ break;
+ }
+ }
+ }
+ if (targetMediaDevices.size() != devices.size()) {
+ devices.removeAll(targetMediaDevices);
+ targetMediaDevices.addAll(devices);
+ }
+ mMediaItemList.clear();
+ mMediaItemList.addAll(
+ targetMediaDevices.stream().map(MediaItem::new).collect(Collectors.toList()));
+ categorizeMediaItems();
+ }
+ }
+
+ private void categorizeMediaItems() {
+ synchronized (mMediaDevicesLock) {
+ //TODO(255124239): do the categorization here
+ mMediaItemList.add(new MediaItem());
+ }
+ }
+
private void attachRangeInfo(List<MediaDevice> devices) {
for (MediaDevice mediaDevice : devices) {
if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) {
@@ -670,6 +766,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
return mMediaDevices;
}
+ public List<MediaItem> getMediaItemList() {
+ return mMediaItemList;
+ }
+
MediaDevice getCurrentConnectedMediaDevice() {
return mLocalMediaManager.getCurrentConnectedDevice();
}
@@ -749,9 +849,19 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
boolean isAnyDeviceTransferring() {
synchronized (mMediaDevicesLock) {
- for (MediaDevice device : mMediaDevices) {
- if (device.getState() == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
- return true;
+ if (isAdvancedLayoutSupported()) {
+ for (MediaItem mediaItem : mMediaItemList) {
+ if (mediaItem.getMediaDevice().isPresent()
+ && mediaItem.getMediaDevice().get().getState()
+ == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
+ return true;
+ }
+ }
+ } else {
+ for (MediaDevice device : mMediaDevices) {
+ if (device.getState() == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
+ return true;
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
index 7d3e82c9d47f..2250d72d8658 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
@@ -96,6 +96,31 @@ public class MediaOutputMetricLogger {
}
/**
+ * Do the metric logging of content switching success.
+ * @param selectedDeviceType string representation of the target media device
+ * @param deviceItemList media item list for device count updating
+ */
+ public void logOutputItemSuccess(String selectedDeviceType, List<MediaItem> deviceItemList) {
+ if (DEBUG) {
+ Log.d(TAG, "logOutputSuccess - selected device: " + selectedDeviceType);
+ }
+
+ updateLoggingMediaItemCount(deviceItemList);
+
+ SysUiStatsLog.write(
+ SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
+ getLoggingDeviceType(mSourceDevice, true),
+ getLoggingDeviceType(mTargetDevice, false),
+ SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__OK,
+ SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NO_ERROR,
+ getLoggingPackageName(),
+ mWiredDeviceCount,
+ mConnectedBluetoothDeviceCount,
+ mRemoteDeviceCount,
+ mAppliedDeviceCountWithinRemoteGroup);
+ }
+
+ /**
* Do the metric logging of volume adjustment.
* @param source the device been adjusted
*/
@@ -166,6 +191,31 @@ public class MediaOutputMetricLogger {
mAppliedDeviceCountWithinRemoteGroup);
}
+ /**
+ * Do the metric logging of content switching failure.
+ * @param deviceItemList media item list for device count updating
+ * @param reason the reason of content switching failure
+ */
+ public void logOutputItemFailure(List<MediaItem> deviceItemList, int reason) {
+ if (DEBUG) {
+ Log.e(TAG, "logRequestFailed - " + reason);
+ }
+
+ updateLoggingMediaItemCount(deviceItemList);
+
+ SysUiStatsLog.write(
+ SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
+ getLoggingDeviceType(mSourceDevice, true),
+ getLoggingDeviceType(mTargetDevice, false),
+ SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__ERROR,
+ getLoggingSwitchOpSubResult(reason),
+ getLoggingPackageName(),
+ mWiredDeviceCount,
+ mConnectedBluetoothDeviceCount,
+ mRemoteDeviceCount,
+ mAppliedDeviceCountWithinRemoteGroup);
+ }
+
private void updateLoggingDeviceCount(List<MediaDevice> deviceList) {
mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0;
mAppliedDeviceCountWithinRemoteGroup = 0;
@@ -196,6 +246,37 @@ public class MediaOutputMetricLogger {
}
}
+ private void updateLoggingMediaItemCount(List<MediaItem> deviceItemList) {
+ mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0;
+ mAppliedDeviceCountWithinRemoteGroup = 0;
+
+ for (MediaItem mediaItem: deviceItemList) {
+ if (mediaItem.getMediaDevice().isPresent()
+ && mediaItem.getMediaDevice().get().isConnected()) {
+ switch (mediaItem.getMediaDevice().get().getDeviceType()) {
+ case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE:
+ case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE:
+ mWiredDeviceCount++;
+ break;
+ case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE:
+ mConnectedBluetoothDeviceCount++;
+ break;
+ case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE:
+ case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE:
+ mRemoteDeviceCount++;
+ break;
+ default:
+ }
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "connected devices:" + " wired: " + mWiredDeviceCount
+ + " bluetooth: " + mConnectedBluetoothDeviceCount
+ + " remote: " + mRemoteDeviceCount);
+ }
+ }
+
private int getLoggingDeviceType(MediaDevice device, boolean isSourceDevice) {
if (device == null) {
return isSourceDevice
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index ac7c70bd1d9e..f60d7ea8d664 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -55,6 +55,7 @@ import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.internal.view.AppearanceRegion;
@@ -125,7 +126,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
private final DisplayManager mDisplayManager;
private Context mWindowContext;
private ScreenPinningNotify mScreenPinningNotify;
- private int mNavigationMode;
+ private int mNavigationMode = -1;
private final Consumer<Rect> mPipListener;
/**
@@ -217,8 +218,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
parseCurrentSysuiState();
mCommandQueue.addCallback(this);
mOverviewProxyService.addCallback(this);
- mEdgeBackGestureHandler.onNavigationModeChanged(
- mNavigationModeController.addListener(this));
+ onNavigationModeChanged(mNavigationModeController.addListener(this));
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.init();
mEdgeBackGestureHandler.onNavBarAttached();
@@ -492,6 +492,11 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
!QuickStepContract.isGesturalMode(mNavigationMode));
}
+ @VisibleForTesting
+ int getNavigationMode() {
+ return mNavigationMode;
+ }
+
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("TaskbarDelegate (displayId=" + mDisplayId + "):");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index f92bbf75d027..8ceee1a950ea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -741,6 +741,14 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
}
};
+ /**
+ * Force all tiles to be redistributed across pages.
+ * Should be called when one of the following changes: rows, columns, number of tiles.
+ */
+ public void forceTilesRedistribution() {
+ mDistributeTiles = true;
+ }
+
public interface PageListener {
int INVALID_PAGE = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 1827eaf3fad1..b2ca6b728113 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -148,6 +148,11 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
}
}
+ @Override
+ protected void onSplitShadeChanged() {
+ ((PagedTileLayout) mView.getOrCreateTileLayout()).forceTilesRedistribution();
+ }
+
/** */
public void setVisibility(int visibility) {
mView.setVisibility(visibility);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index dd88c83949fb..60d2c177c7cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -96,17 +96,23 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
/* newOrientation= */ newConfig.orientation,
/* containerName= */ mView.getDumpableTag());
+ boolean previousSplitShadeState = mShouldUseSplitNotificationShade;
mShouldUseSplitNotificationShade =
LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
mLastOrientation = newConfig.orientation;
switchTileLayoutIfNeeded();
onConfigurationChanged();
+ if (previousSplitShadeState != mShouldUseSplitNotificationShade) {
+ onSplitShadeChanged();
+ }
}
};
protected void onConfigurationChanged() { }
+ protected void onSplitShadeChanged() { }
+
private final Function1<Boolean, Unit> mMediaHostVisibilityListener = (visible) -> {
if (mMediaVisibilityChangedListener != null) {
mMediaVisibilityChangedListener.accept(visible);
@@ -264,14 +270,6 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
}
}
}
- protected QSTile getTile(String subPanel) {
- for (int i = 0; i < mRecords.size(); i++) {
- if (subPanel.equals(mRecords.get(i).tile.getTileSpec())) {
- return mRecords.get(i).tile;
- }
- }
- return mHost.createTile(subPanel);
- }
boolean areThereTiles() {
return !mRecords.isEmpty();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index 5dbf0f8dcdce..0bce1f728e18 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -57,6 +57,7 @@ import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
@@ -770,13 +771,6 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener {
}
}
- private boolean isFinancedDevice() {
- return mSecurityController.isDeviceManaged()
- && mSecurityController.getDeviceOwnerType(
- mSecurityController.getDeviceOwnerComponentOnAnyUser())
- == DEVICE_OWNER_TYPE_FINANCED;
- }
-
protected class VpnSpan extends ClickableSpan {
@Override
public void onClick(View widget) {
@@ -797,4 +791,18 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener {
return 314159257; // prime
}
}
+
+ // TODO(b/259908270): remove and inline direct call to mSecurityController.isFinancedDevice()
+ private boolean isFinancedDevice() {
+ if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG,
+ DevicePolicyManager.ADD_ISFINANCED_FEVICE_DEFAULT)) {
+ return mSecurityController.isFinancedDevice();
+ } else {
+ return mSecurityController.isDeviceManaged()
+ && mSecurityController.getDeviceOwnerType(
+ mSecurityController.getDeviceOwnerComponentOnAnyUser())
+ == DEVICE_OWNER_TYPE_FINANCED;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 507dec67b11a..ee89a48fbaaf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2141,7 +2141,6 @@ public final class NotificationPanelViewController implements Dumpable {
if ((h > touchSlop || (h < -touchSlop && mQsExpanded))
&& Math.abs(h) > Math.abs(x - mInitialTouchX)
&& shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
- debugLog("onQsIntercept - start tracking expansion");
mView.getParent().requestDisallowInterceptTouchEvent(true);
mShadeLog.onQsInterceptMoveQsTrackingEnabled(h);
mQsTracking = true;
@@ -2352,7 +2351,7 @@ public final class NotificationPanelViewController implements Dumpable {
if (!mSplitShadeEnabled
&& computeQsExpansionFraction() <= 0.01 && getExpandedFraction() < 1.0) {
mShadeLog.logMotionEvent(event,
- "handleQsTouch: QQS touched while shade collapsing");
+ "handleQsTouch: QQS touched while shade collapsing, QS tracking disabled");
mQsTracking = false;
}
if (!mQsExpandImmediate && mQsTracking) {
@@ -5796,12 +5795,9 @@ public final class NotificationPanelViewController implements Dumpable {
/** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */
public boolean onInterceptTouchEvent(MotionEvent event) {
mShadeLog.logMotionEvent(event, "NPVC onInterceptTouchEvent");
- if (SPEW_LOGCAT) {
- Log.v(TAG,
- "NPVC onInterceptTouchEvent (" + event.getId() + "): (" + event.getX()
- + "," + event.getY() + ")");
- }
if (mQs.disallowPanelTouches()) {
+ mShadeLog.logMotionEvent(event,
+ "NPVC not intercepting touch, panel touches disallowed");
return false;
}
initDownStates(event);
@@ -5834,8 +5830,15 @@ public final class NotificationPanelViewController implements Dumpable {
+ "QsIntercept");
return true;
}
- if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted
- && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
+
+ if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled) {
+ mShadeLog.logNotInterceptingTouchInstantExpanding(mInstantExpanding,
+ !mNotificationsDragEnabled, mTouchDisabled);
+ return false;
+ }
+ if (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+ mShadeLog.logMotionEventStatusBarState(event, mStatusBarStateController.getState(),
+ "NPVC MotionEvent not intercepted: non-down action, motion was aborted");
return false;
}
@@ -5890,6 +5893,9 @@ public final class NotificationPanelViewController implements Dumpable {
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
+ mShadeLog.logMotionEventStatusBarState(event,
+ mStatusBarStateController.getState(),
+ "onInterceptTouchEvent: pointer down action");
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
mMotionAborted = true;
mVelocityTracker.clear();
@@ -5931,7 +5937,8 @@ public final class NotificationPanelViewController implements Dumpable {
// events are received in this handler with identical downTimes. Until the
// source of the issue can be located, detect this case and ignore.
// see b/193350347
- Log.w(TAG, "Duplicate down event detected... ignoring");
+ mShadeLog.logMotionEvent(event,
+ "onTouch: duplicate down event detected... ignoring");
return true;
}
mLastTouchDownTime = event.getDownTime();
@@ -5939,6 +5946,8 @@ public final class NotificationPanelViewController implements Dumpable {
if (mQsFullyExpanded && mQs != null && mQs.disallowPanelTouches()) {
+ mShadeLog.logMotionEvent(event,
+ "onTouch: ignore touch, panel touches disallowed and qs fully expanded");
return false;
}
@@ -5946,6 +5955,8 @@ public final class NotificationPanelViewController implements Dumpable {
// otherwise user would be able to pull down QS or expand the shade.
if (mCentralSurfaces.isBouncerShowingScrimmed()
|| mCentralSurfaces.isBouncerShowingOverDream()) {
+ mShadeLog.logMotionEvent(event,
+ "onTouch: ignore touch, bouncer scrimmed or showing over dream");
return false;
}
@@ -6003,15 +6014,17 @@ public final class NotificationPanelViewController implements Dumpable {
private boolean handleTouch(MotionEvent event) {
if (mInstantExpanding) {
- mShadeLog.logMotionEvent(event, "onTouch: touch ignored due to instant expanding");
+ mShadeLog.logMotionEvent(event,
+ "handleTouch: touch ignored due to instant expanding");
return false;
}
if (mTouchDisabled && event.getActionMasked() != MotionEvent.ACTION_CANCEL) {
- mShadeLog.logMotionEvent(event, "onTouch: non-cancel action, touch disabled");
+ mShadeLog.logMotionEvent(event, "handleTouch: non-cancel action, touch disabled");
return false;
}
if (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
- mShadeLog.logMotionEvent(event, "onTouch: non-down action, motion was aborted");
+ mShadeLog.logMotionEventStatusBarState(event, mStatusBarStateController.getState(),
+ "handleTouch: non-down action, motion was aborted");
return false;
}
@@ -6021,7 +6034,7 @@ public final class NotificationPanelViewController implements Dumpable {
// Turn off tracking if it's on or the shade can get stuck in the down position.
onTrackingStopped(true /* expand */);
}
- mShadeLog.logMotionEvent(event, "onTouch: drag not enabled");
+ mShadeLog.logMotionEvent(event, "handleTouch: drag not enabled");
return false;
}
@@ -6094,6 +6107,9 @@ public final class NotificationPanelViewController implements Dumpable {
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
+ mShadeLog.logMotionEventStatusBarState(event,
+ mStatusBarStateController.getState(),
+ "handleTouch: pointer down action");
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
mMotionAborted = true;
endMotionEvent(event, x, y, true /* forceCancel */);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 40ed40a767e5..0b59af3435ca 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -98,6 +98,29 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) {
)
}
+ fun logMotionEventStatusBarState(event: MotionEvent, statusBarState: Int, message: String) {
+ log(
+ LogLevel.VERBOSE,
+ {
+ str1 = message
+ long1 = event.eventTime
+ long2 = event.downTime
+ int1 = event.action
+ int2 = statusBarState
+ double1 = event.y.toDouble()
+ },
+ {
+ "$str1\neventTime=$long1,downTime=$long2,y=$double1,action=$int1," +
+ "statusBarState=${when (int2) {
+ 0 -> "SHADE"
+ 1 -> "KEYGUARD"
+ 2 -> "SHADE_LOCKED"
+ else -> "UNKNOWN:$int2"
+ }}"
+ }
+ )
+ }
+
fun logExpansionChanged(
message: String,
fraction: Float,
@@ -164,4 +187,19 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) {
"tap to be detected: proximityIsNotNear: $bool1, isNotFalseTap: $bool2"
})
}
+
+ fun logNotInterceptingTouchInstantExpanding(
+ instantExpanding: Boolean,
+ notificationsDragEnabled: Boolean,
+ touchDisabled: Boolean
+ ) {
+ log(LogLevel.VERBOSE, {
+ bool1 = instantExpanding
+ bool2 = notificationsDragEnabled
+ bool3 = touchDisabled
+ }, {
+ "NPVC not intercepting touch, instantExpanding: $bool1, " +
+ "!notificationsDragEnabled: $bool2, touchDisabled: $bool3"
+ })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0f27420e22b0..e39879dd166e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -61,6 +61,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.View;
@@ -413,14 +414,25 @@ public class KeyguardIndicationController {
private CharSequence getDisclosureText(@Nullable CharSequence organizationName) {
final Resources packageResources = mContext.getResources();
+
+ // TODO(b/259908270): remove and inline
+ boolean isFinanced;
+ if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG,
+ DevicePolicyManager.ADD_ISFINANCED_FEVICE_DEFAULT)) {
+ isFinanced = mDevicePolicyManager.isFinancedDevice();
+ } else {
+ isFinanced = mDevicePolicyManager.isDeviceManaged()
+ && mDevicePolicyManager.getDeviceOwnerType(
+ mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+ == DEVICE_OWNER_TYPE_FINANCED;
+ }
+
if (organizationName == null) {
return mDevicePolicyManager.getResources().getString(
KEYGUARD_MANAGEMENT_DISCLOSURE,
() -> packageResources.getString(R.string.do_disclosure_generic));
- } else if (mDevicePolicyManager.isDeviceManaged()
- && mDevicePolicyManager.getDeviceOwnerType(
- mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
- == DEVICE_OWNER_TYPE_FINANCED) {
+ } else if (isFinanced) {
return packageResources.getString(R.string.do_financed_disclosure_with_name,
organizationName);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 336356eae364..b9074f0b9e2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -68,7 +68,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.LongRunning;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
@@ -225,15 +225,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
/**
* Construct this controller object and register for updates.
- *
- * {@code @LongRunning} looper and bgExecutor instead {@code @Background} ones are used to
- * address the b/246456655. This can be reverted after b/240663726 is fixed.
*/
@Inject
public NetworkControllerImpl(
Context context,
- @LongRunning Looper bgLooper,
- @LongRunning Executor bgExecutor,
+ @Background Looper bgLooper,
+ @Background Executor bgExecutor,
SubscriptionManager subscriptionManager,
CallbackHandler callbackHandler,
DeviceProvisionedController deviceProvisionedController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 8bb2d46c80d9..56d3b7cf788f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.lockscreen
import android.app.PendingIntent
+import android.app.WallpaperManager
import android.app.smartspace.SmartspaceConfig
import android.app.smartspace.SmartspaceManager
import android.app.smartspace.SmartspaceSession
@@ -390,7 +391,8 @@ class LockscreenSmartspaceController @Inject constructor(
}
private fun updateTextColorFromWallpaper() {
- if (!regionSamplingEnabled) {
+ val wallpaperManager = WallpaperManager.getInstance(context)
+ if (!regionSamplingEnabled || wallpaperManager.lockScreenWallpaperExists()) {
val wallpaperTextColor =
Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor)
smartspaceViews.forEach { it.setPrimaryTextColor(wallpaperTextColor) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 3e2dd053d938..aeae89cb3223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -244,7 +244,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
- logger.logOnDozeAmountChanged(linear, eased)
+ logger.logOnDozeAmountChanged(linear = linear, eased = eased)
if (overrideDozeAmountIfAnimatingScreenOff(linear)) {
return
}
@@ -263,6 +263,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
fun setDozeAmount(linear: Float, eased: Float, source: String) {
val changed = linear != mLinearDozeAmount
+ logger.logSetDozeAmount(linear, eased, source, statusBarStateController.state, changed)
mLinearDozeAmount = linear
mDozeAmount = eased
mDozeAmountSource = source
@@ -276,7 +277,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
override fun onStateChanged(newState: Int) {
- logger.logOnStateChanged(newState)
+ logger.logOnStateChanged(newState = newState, storedState = state)
if (state == StatusBarState.SHADE && newState == StatusBarState.SHADE) {
// The SHADE -> SHADE transition is only possible as part of cancelling the screen-off
// animation (e.g. by fingerprint unlock). This is done because the system is in an
@@ -324,12 +325,8 @@ class NotificationWakeUpCoordinator @Inject constructor(
private fun overrideDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
if (statusBarStateController.state == StatusBarState.KEYGUARD) {
- logger.logSetDozeAmount("1.0", "1.0",
- "Override: bypass (keyguard)", StatusBarState.KEYGUARD)
setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)")
} else {
- logger.logSetDozeAmount("0.0", "0.0",
- "Override: bypass (shade)", statusBarStateController.state)
setDozeAmount(0f, 0f, source = "Override: bypass (shade)")
}
return true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index b40ce25c58d2..de18b0c4307d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -16,22 +16,33 @@ package com.android.systemui.statusbar.notification
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.statusbar.StatusBarState
import javax.inject.Inject
class NotificationWakeUpCoordinatorLogger
@Inject
constructor(@NotificationLog private val buffer: LogBuffer) {
- fun logSetDozeAmount(linear: String, eased: String, source: String, state: Int) {
+ fun logSetDozeAmount(
+ linear: Float,
+ eased: Float,
+ source: String,
+ state: Int,
+ changed: Boolean,
+ ) {
buffer.log(
TAG,
DEBUG,
{
- str1 = linear
- str2 = eased
+ double1 = linear.toDouble()
+ str2 = eased.toString()
str3 = source
int1 = state
+ bool1 = changed
},
- { "setDozeAmount: linear: $str1, eased: $str2, source: $str3, state: $int1" }
+ {
+ "setDozeAmount(linear=$double1, eased=$str2, source=$str3)" +
+ " state=${StatusBarState.toString(int1)} changed=$bool1"
+ }
)
}
@@ -43,12 +54,23 @@ constructor(@NotificationLog private val buffer: LogBuffer) {
double1 = linear.toDouble()
str2 = eased.toString()
},
- { "onDozeAmountChanged($double1, $str2)" }
+ { "onDozeAmountChanged(linear=$double1, eased=$str2)" }
)
}
- fun logOnStateChanged(newState: Int) {
- buffer.log(TAG, DEBUG, { int1 = newState }, { "onStateChanged($int1)" })
+ fun logOnStateChanged(newState: Int, storedState: Int) {
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = newState
+ int2 = storedState
+ },
+ {
+ "onStateChanged(newState=${StatusBarState.toString(int1)})" +
+ " stored=${StatusBarState.toString(int2)}"
+ }
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 9da94ce968c7..4133802189a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -119,6 +119,9 @@ constructor(
// Don't apply the filter to (non-promoted) group summaries
// - summary will be pruned if necessary, depending on if children are filtered
entry.parent?.summary == entry -> false
+ // Check that the entry satisfies certain characteristics that would bypass the
+ // filter
+ shouldIgnoreUnseenCheck(entry) -> false
else -> true
}.also { hasFiltered -> hasFilteredAnyNotifs = hasFilteredAnyNotifs || hasFiltered }
@@ -134,6 +137,13 @@ constructor(
keyguardNotificationVisibilityProvider.shouldHideNotification(entry)
}
+ private fun shouldIgnoreUnseenCheck(entry: NotificationEntry): Boolean =
+ when {
+ entry.isMediaNotification -> true
+ entry.sbn.isOngoing -> true
+ else -> false
+ }
+
// TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
// these same updates
private fun setupInvalidateNotifListCallbacks() {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiDebug.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiDebug.kt
new file mode 100644
index 000000000000..d9e3f8fbf146
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiDebug.kt
@@ -0,0 +1,16 @@
+package com.android.systemui.statusbar.notification.fsi
+
+class FsiDebug {
+
+ companion object {
+ private const val debugTag = "FsiDebug"
+ private const val debug = true
+
+ fun log(s: Any) {
+ if (!debug) {
+ return
+ }
+ android.util.Log.d(debugTag, "$s")
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
index 6cf4bf318c99..7136cad22c16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -25,6 +25,79 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
*/
public interface NotificationInterruptStateProvider {
/**
+ * Enum representing a decision of whether to show a full screen intent. While many of the
+ * relevant properties could overlap, the decision represents the deciding factor for whether
+ * the full screen intent should or shouldn't launch.
+ */
+ enum FullScreenIntentDecision {
+ /**
+ * No full screen intent included, so there is nothing to show.
+ */
+ NO_FULL_SCREEN_INTENT(false),
+ /**
+ * Suppressed by DND settings.
+ */
+ NO_FSI_SUPPRESSED_BY_DND(false),
+ /**
+ * Full screen intent was suppressed *only* by DND, and if not for DND would have shown. We
+ * track this separately in order to allow the intent to be shown if the DND decision
+ * changes.
+ */
+ NO_FSI_SUPPRESSED_ONLY_BY_DND(false),
+ /**
+ * Notification importance not high enough to show FSI.
+ */
+ NO_FSI_NOT_IMPORTANT_ENOUGH(false),
+ /**
+ * Notification should not FSI due to having suppressive GroupAlertBehavior. This blocks a
+ * potentially malicious use of flags that previously allowed apps to escalate a HUN to an
+ * FSI even while the device was unlocked.
+ */
+ NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(false),
+ /**
+ * Device screen is off, so the FSI should launch.
+ */
+ FSI_DEVICE_NOT_INTERACTIVE(true),
+ /**
+ * Device is currently dreaming, so FSI should launch.
+ */
+ FSI_DEVICE_IS_DREAMING(true),
+ /**
+ * Keyguard is showing, so FSI should launch.
+ */
+ FSI_KEYGUARD_SHOWING(true),
+ /**
+ * The notification is expected to show heads-up, so FSI is not needed.
+ */
+ NO_FSI_EXPECTED_TO_HUN(false),
+ /**
+ * The notification is not expected to HUN while the keyguard is occluded, so show FSI.
+ */
+ FSI_KEYGUARD_OCCLUDED(true),
+ /**
+ * The notification is not expected to HUN when the keyguard is showing but not occluded,
+ * which likely means that the shade is showing over the lockscreen; show FSI in this case.
+ */
+ FSI_LOCKED_SHADE(true),
+ /**
+ * FSI requires keyguard to be showing, but there is no keyguard. This is a (potentially
+ * malicious) warning state where we suppress the FSI because the device is in use knowing
+ * that the HUN will probably not display.
+ */
+ NO_FSI_NO_HUN_OR_KEYGUARD(false),
+ /**
+ * No conditions blocking FSI launch.
+ */
+ FSI_EXPECTED_NOT_TO_HUN(true);
+
+ public final boolean shouldLaunch;
+
+ FullScreenIntentDecision(boolean shouldLaunch) {
+ this.shouldLaunch = shouldLaunch;
+ }
+ }
+
+ /**
* If the device is awake (not dozing):
* Whether the notification should peek in from the top and alert the user.
*
@@ -66,6 +139,27 @@ public interface NotificationInterruptStateProvider {
boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry);
/**
+ * Whether an entry's full screen intent would be launched.
+ *
+ * This method differs from shouldLaunchFullScreenIntentWhenAdded by returning more information
+ * on the decision, and only optionally logging the outcome. It should be used in cases where
+ * the caller needs to know what the decision would be, but may not actually launch the full
+ * screen intent.
+ *
+ * @param entry the entry to evaluate
+ * @return FullScreenIntentDecision representing the decision for whether to show the intent
+ */
+ FullScreenIntentDecision getFullScreenIntentDecision(NotificationEntry entry);
+
+ /**
+ * Write the full screen launch decision for the given entry to logs.
+ *
+ * @param entry the NotificationEntry for which the decision applies
+ * @param decision reason for launch or no-launch of FSI for entry
+ */
+ void logFullScreenIntentDecision(NotificationEntry entry, FullScreenIntentDecision decision);
+
+ /**
* Add a component that can suppress visual interruptions.
*/
void addSuppressor(NotificationInterruptSuppressor suppressor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index ec5bd6894283..d9dacfd0e27c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -211,20 +211,49 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
*/
@Override
public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
+ FullScreenIntentDecision decision = getFullScreenIntentDecision(entry);
+ logFullScreenIntentDecision(entry, decision);
+ return decision.shouldLaunch;
+ }
+
+ // Given whether the relevant entry was suppressed by DND, and the full screen intent launch
+ // decision independent of the DND decision, returns the combined FullScreenIntentDecision that
+ // results. If the entry was suppressed by DND but the decision otherwise would launch the
+ // FSI, then it is suppressed *only* by DND, whereas (because the DND decision happens before
+ // all others) if the entry would not otherwise have launched the FSI, DND is the effective
+ // suppressor.
+ //
+ // If the entry was not suppressed by DND, just returns the given decision.
+ private FullScreenIntentDecision getDecisionGivenSuppression(FullScreenIntentDecision decision,
+ boolean suppressedByDND) {
+ if (suppressedByDND) {
+ return decision.shouldLaunch
+ ? FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND
+ : FullScreenIntentDecision.NO_FSI_SUPPRESSED_BY_DND;
+ }
+ return decision;
+ }
+
+ @Override
+ public FullScreenIntentDecision getFullScreenIntentDecision(NotificationEntry entry) {
if (entry.getSbn().getNotification().fullScreenIntent == null) {
- return false;
+ return FullScreenIntentDecision.NO_FULL_SCREEN_INTENT;
}
+ // Boolean indicating whether this FSI would have been suppressed by DND. Because we
+ // want to be able to identify when something would have shown an FSI if not for being
+ // suppressed, we need to keep track of this value for future decisions.
+ boolean suppressedByDND = false;
+
// Never show FSI when suppressed by DND
if (entry.shouldSuppressFullScreenIntent()) {
- mLogger.logNoFullscreen(entry, "Suppressed by DND");
- return false;
+ suppressedByDND = true;
}
// Never show FSI if importance is not HIGH
if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) {
- mLogger.logNoFullscreen(entry, "Not important enough");
- return false;
+ return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_NOT_IMPORTANT_ENOUGH,
+ suppressedByDND);
}
// If the notification has suppressive GroupAlertBehavior, block FSI and warn.
@@ -232,36 +261,35 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
// b/231322873: Detect and report an event when a notification has both an FSI and a
// suppressive groupAlertBehavior, and now correctly block the FSI from firing.
- final int uid = entry.getSbn().getUid();
- final String packageName = entry.getSbn().getPackageName();
- android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "groupAlertBehavior");
- mUiEventLogger.log(FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR, uid, packageName);
- mLogger.logNoFullscreenWarning(entry, "GroupAlertBehavior will prevent HUN");
- return false;
+ return getDecisionGivenSuppression(
+ FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR,
+ suppressedByDND);
}
// If the screen is off, then launch the FullScreenIntent
if (!mPowerManager.isInteractive()) {
- mLogger.logFullscreen(entry, "Device is not interactive");
- return true;
+ return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE,
+ suppressedByDND);
}
// If the device is currently dreaming, then launch the FullScreenIntent
if (isDreaming()) {
- mLogger.logFullscreen(entry, "Device is dreaming");
- return true;
+ return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_DEVICE_IS_DREAMING,
+ suppressedByDND);
}
// If the keyguard is showing, then launch the FullScreenIntent
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
- mLogger.logFullscreen(entry, "Keyguard is showing");
- return true;
+ return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_KEYGUARD_SHOWING,
+ suppressedByDND);
}
// If the notification should HUN, then we don't need FSI
- if (shouldHeadsUp(entry)) {
- mLogger.logNoFullscreen(entry, "Expected to HUN");
- return false;
+ // Because this is not the heads-up decision-making point, and checking whether it would
+ // HUN, don't log this specific check.
+ if (checkHeadsUp(entry, /* log= */ false)) {
+ return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN,
+ suppressedByDND);
}
// Check whether FSI requires the keyguard to be showing.
@@ -270,27 +298,77 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
// If notification won't HUN and keyguard is showing, launch the FSI.
if (mKeyguardStateController.isShowing()) {
if (mKeyguardStateController.isOccluded()) {
- mLogger.logFullscreen(entry, "Expected not to HUN while keyguard occluded");
+ return getDecisionGivenSuppression(
+ FullScreenIntentDecision.FSI_KEYGUARD_OCCLUDED,
+ suppressedByDND);
} else {
// Likely LOCKED_SHADE, but launch FSI anyway
- mLogger.logFullscreen(entry, "Keyguard is showing and not occluded");
+ return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_LOCKED_SHADE,
+ suppressedByDND);
}
- return true;
}
// Detect the case determined by b/231322873 to launch FSI while device is in use,
// as blocked by the correct implementation, and report the event.
- final int uid = entry.getSbn().getUid();
- final String packageName = entry.getSbn().getPackageName();
- android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "no hun or keyguard");
- mUiEventLogger.log(FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD, uid, packageName);
- mLogger.logNoFullscreenWarning(entry, "Expected not to HUN while not on keyguard");
- return false;
+ return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD,
+ suppressedByDND);
}
// If the notification won't HUN for some other reason (DND/snooze/etc), launch FSI.
- mLogger.logFullscreen(entry, "Expected not to HUN");
- return true;
+ return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_EXPECTED_NOT_TO_HUN,
+ suppressedByDND);
+ }
+
+ @Override
+ public void logFullScreenIntentDecision(NotificationEntry entry,
+ FullScreenIntentDecision decision) {
+ final int uid = entry.getSbn().getUid();
+ final String packageName = entry.getSbn().getPackageName();
+ switch (decision) {
+ case NO_FULL_SCREEN_INTENT:
+ return;
+ case NO_FSI_SUPPRESSED_BY_DND:
+ case NO_FSI_SUPPRESSED_ONLY_BY_DND:
+ mLogger.logNoFullscreen(entry, "Suppressed by DND");
+ return;
+ case NO_FSI_NOT_IMPORTANT_ENOUGH:
+ mLogger.logNoFullscreen(entry, "Not important enough");
+ return;
+ case NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR:
+ android.util.EventLog.writeEvent(0x534e4554, "231322873", uid,
+ "groupAlertBehavior");
+ mUiEventLogger.log(FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR, uid,
+ packageName);
+ mLogger.logNoFullscreenWarning(entry, "GroupAlertBehavior will prevent HUN");
+ return;
+ case FSI_DEVICE_NOT_INTERACTIVE:
+ mLogger.logFullscreen(entry, "Device is not interactive");
+ return;
+ case FSI_DEVICE_IS_DREAMING:
+ mLogger.logFullscreen(entry, "Device is dreaming");
+ return;
+ case FSI_KEYGUARD_SHOWING:
+ mLogger.logFullscreen(entry, "Keyguard is showing");
+ return;
+ case NO_FSI_EXPECTED_TO_HUN:
+ mLogger.logNoFullscreen(entry, "Expected to HUN");
+ return;
+ case FSI_KEYGUARD_OCCLUDED:
+ mLogger.logFullscreen(entry,
+ "Expected not to HUN while keyguard occluded");
+ return;
+ case FSI_LOCKED_SHADE:
+ mLogger.logFullscreen(entry, "Keyguard is showing and not occluded");
+ return;
+ case NO_FSI_NO_HUN_OR_KEYGUARD:
+ android.util.EventLog.writeEvent(0x534e4554, "231322873", uid,
+ "no hun or keyguard");
+ mUiEventLogger.log(FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD, uid, packageName);
+ mLogger.logNoFullscreenWarning(entry, "Expected not to HUN while not on keyguard");
+ return;
+ case FSI_EXPECTED_NOT_TO_HUN:
+ mLogger.logFullscreen(entry, "Expected not to HUN");
+ }
}
private boolean isDreaming() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index c217ab3b42e3..69f7c71dafba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -22,6 +22,8 @@ import android.graphics.Rect;
import android.util.MathUtils;
import android.view.View;
+import androidx.annotation.NonNull;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.R;
@@ -197,6 +199,11 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
updateHeadsUpAndPulsingRoundness(entry);
}
+ @Override
+ public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) {
+ updateHeadsUpAndPulsingRoundness(entry);
+ }
+
private void updateTopEntry() {
NotificationEntry newEntry = null;
if (shouldBeVisible()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index d4dc1dc197a5..348357445223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -475,9 +475,6 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
* mKeyguardStatusBarAnimateAlpha
* (1.0f - mKeyguardHeadsUpShowingAmount);
- if (newAlpha != mView.getAlpha() && (newAlpha == 0 || newAlpha == 1)) {
- mLogger.logStatusBarCalculatedAlpha(newAlpha);
- }
}
boolean hideForBypass =
@@ -500,10 +497,6 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
if (mDisableStateTracker.isDisabled()) {
visibility = View.INVISIBLE;
}
- if (visibility != mView.getVisibility()) {
- mLogger.logStatusBarAlphaVisibility(visibility, alpha,
- StatusBarState.toString(mStatusBarState));
- }
mView.setAlpha(alpha);
mView.setVisibility(visibility);
}
@@ -608,10 +601,6 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
* @param alpha a value between 0 and 1. -1 if the value is to be reset/ignored.
*/
public void setAlpha(float alpha) {
- if (mExplicitAlpha != alpha && (mExplicitAlpha == -1 || alpha == -1)) {
- // logged if value changed to ignored or from ignored
- mLogger.logStatusBarExplicitAlpha(alpha);
- }
mExplicitAlpha = alpha;
updateViewState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index 2a93844acd5b..3be14bc867a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -36,9 +36,14 @@ public interface SecurityController extends CallbackController<SecurityControlle
String getProfileOwnerName();
CharSequence getDeviceOwnerOrganizationName();
CharSequence getWorkProfileOrganizationName();
+
+ boolean isFinancedDevice();
+
/** Device owner component even if not on this user. **/
ComponentName getDeviceOwnerComponentOnAnyUser();
+ // TODO(b/259908270): remove
/** Device owner type for a device owner. **/
+ @Deprecated
int getDeviceOwnerType(ComponentName admin);
boolean isNetworkLoggingEnabled();
boolean isVpnEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index ba947149d287..03656f000c07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -254,6 +254,7 @@ public class SecurityControllerImpl implements SecurityController {
return mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();
}
+ // TODO(b/259908270): remove
@Override
@DeviceOwnerType
public int getDeviceOwnerType(@NonNull ComponentName admin) {
@@ -261,6 +262,11 @@ public class SecurityControllerImpl implements SecurityController {
}
@Override
+ public boolean isFinancedDevice() {
+ return mDevicePolicyManager.isFinancedDevice();
+ }
+
+ @Override
public boolean isNetworkLoggingEnabled() {
return mDevicePolicyManager.isNetworkLoggingEnabled(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
new file mode 100644
index 000000000000..3e111e6de785
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.stylus
+
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.hardware.input.InputManager
+import android.os.Handler
+import android.util.ArrayMap
+import android.util.Log
+import android.view.InputDevice
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import java.util.concurrent.CopyOnWriteArrayList
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * A class which keeps track of InputDevice events related to stylus devices, and notifies
+ * registered callbacks of stylus events.
+ */
+@SysUISingleton
+class StylusManager
+@Inject
+constructor(
+ private val inputManager: InputManager,
+ private val bluetoothAdapter: BluetoothAdapter,
+ @Background private val handler: Handler,
+ @Background private val executor: Executor,
+) : InputManager.InputDeviceListener, BluetoothAdapter.OnMetadataChangedListener {
+
+ private val stylusCallbacks: CopyOnWriteArrayList<StylusCallback> = CopyOnWriteArrayList()
+ private val stylusBatteryCallbacks: CopyOnWriteArrayList<StylusBatteryCallback> =
+ CopyOnWriteArrayList()
+ // This map should only be accessed on the handler
+ private val inputDeviceAddressMap: MutableMap<Int, String?> = ArrayMap()
+
+ /**
+ * Starts listening to InputManager InputDevice events. Will also load the InputManager snapshot
+ * at time of starting.
+ */
+ fun startListener() {
+ addExistingStylusToMap()
+ inputManager.registerInputDeviceListener(this, handler)
+ }
+
+ /** Registers a StylusCallback to listen to stylus events. */
+ fun registerCallback(callback: StylusCallback) {
+ stylusCallbacks.add(callback)
+ }
+
+ /** Unregisters a StylusCallback. If StylusCallback is not registered, is a no-op. */
+ fun unregisterCallback(callback: StylusCallback) {
+ stylusCallbacks.remove(callback)
+ }
+
+ fun registerBatteryCallback(callback: StylusBatteryCallback) {
+ stylusBatteryCallbacks.add(callback)
+ }
+
+ fun unregisterBatteryCallback(callback: StylusBatteryCallback) {
+ stylusBatteryCallbacks.remove(callback)
+ }
+
+ override fun onInputDeviceAdded(deviceId: Int) {
+ val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return
+ if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return
+
+ // TODO(b/257936830): get address once input api available
+ val btAddress: String? = null
+ inputDeviceAddressMap[deviceId] = btAddress
+ executeStylusCallbacks { cb -> cb.onStylusAdded(deviceId) }
+
+ if (btAddress != null) {
+ onStylusBluetoothConnected(btAddress)
+ executeStylusCallbacks { cb -> cb.onStylusBluetoothConnected(deviceId, btAddress) }
+ }
+ }
+
+ override fun onInputDeviceChanged(deviceId: Int) {
+ val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return
+ if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return
+
+ // TODO(b/257936830): get address once input api available
+ val currAddress: String? = null
+ val prevAddress: String? = inputDeviceAddressMap[deviceId]
+ inputDeviceAddressMap[deviceId] = currAddress
+
+ if (prevAddress == null && currAddress != null) {
+ onStylusBluetoothConnected(currAddress)
+ executeStylusCallbacks { cb -> cb.onStylusBluetoothConnected(deviceId, currAddress) }
+ }
+
+ if (prevAddress != null && currAddress == null) {
+ onStylusBluetoothDisconnected(prevAddress)
+ executeStylusCallbacks { cb -> cb.onStylusBluetoothDisconnected(deviceId, prevAddress) }
+ }
+ }
+
+ override fun onInputDeviceRemoved(deviceId: Int) {
+ if (!inputDeviceAddressMap.contains(deviceId)) return
+
+ val btAddress: String? = inputDeviceAddressMap[deviceId]
+ inputDeviceAddressMap.remove(deviceId)
+ if (btAddress != null) {
+ onStylusBluetoothDisconnected(btAddress)
+ executeStylusCallbacks { cb -> cb.onStylusBluetoothDisconnected(deviceId, btAddress) }
+ }
+ executeStylusCallbacks { cb -> cb.onStylusRemoved(deviceId) }
+ }
+
+ override fun onMetadataChanged(device: BluetoothDevice, key: Int, value: ByteArray?) {
+ handler.post executeMetadataChanged@{
+ if (key != BluetoothDevice.METADATA_MAIN_CHARGING || value == null)
+ return@executeMetadataChanged
+
+ val inputDeviceId: Int =
+ inputDeviceAddressMap.filterValues { it == device.address }.keys.firstOrNull()
+ ?: return@executeMetadataChanged
+
+ val isCharging = String(value) == "true"
+
+ executeStylusBatteryCallbacks { cb ->
+ cb.onStylusBluetoothChargingStateChanged(inputDeviceId, device, isCharging)
+ }
+ }
+ }
+
+ private fun onStylusBluetoothConnected(btAddress: String) {
+ val device: BluetoothDevice = bluetoothAdapter.getRemoteDevice(btAddress) ?: return
+ try {
+ bluetoothAdapter.addOnMetadataChangedListener(device, executor, this)
+ } catch (e: IllegalArgumentException) {
+ Log.e(TAG, "$e: Metadata listener already registered for device. Ignoring.")
+ }
+ }
+
+ private fun onStylusBluetoothDisconnected(btAddress: String) {
+ val device: BluetoothDevice = bluetoothAdapter.getRemoteDevice(btAddress) ?: return
+ try {
+ bluetoothAdapter.removeOnMetadataChangedListener(device, this)
+ } catch (e: IllegalArgumentException) {
+ Log.e(TAG, "$e: Metadata listener does not exist for device. Ignoring.")
+ }
+ }
+
+ private fun executeStylusCallbacks(run: (cb: StylusCallback) -> Unit) {
+ stylusCallbacks.forEach(run)
+ }
+
+ private fun executeStylusBatteryCallbacks(run: (cb: StylusBatteryCallback) -> Unit) {
+ stylusBatteryCallbacks.forEach(run)
+ }
+
+ private fun addExistingStylusToMap() {
+ for (deviceId: Int in inputManager.inputDeviceIds) {
+ val device: InputDevice = inputManager.getInputDevice(deviceId) ?: continue
+ if (device.supportsSource(InputDevice.SOURCE_STYLUS)) {
+ // TODO(b/257936830): get address once input api available
+ inputDeviceAddressMap[deviceId] = null
+ }
+ }
+ }
+
+ /** Callback interface to receive events from the StylusManager. */
+ interface StylusCallback {
+ fun onStylusAdded(deviceId: Int) {}
+ fun onStylusRemoved(deviceId: Int) {}
+ fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) {}
+ fun onStylusBluetoothDisconnected(deviceId: Int, btAddress: String) {}
+ }
+
+ /** Callback interface to receive stylus battery events from the StylusManager. */
+ interface StylusBatteryCallback {
+ fun onStylusBluetoothChargingStateChanged(
+ inputDeviceId: Int,
+ btDevice: BluetoothDevice,
+ isCharging: Boolean
+ ) {}
+ }
+
+ companion object {
+ private val TAG = StylusManager::class.simpleName.orEmpty()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index 13ac39c77c93..209d93f786a2 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -92,5 +92,7 @@ interface SysUIUnfoldComponent {
fun getUnfoldTransitionWallpaperController(): UnfoldTransitionWallpaperController
+ fun getUnfoldHapticsPlayer(): UnfoldHapticsPlayer
+
fun getUnfoldLightRevealOverlayAnimation(): UnfoldLightRevealOverlayAnimation
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
new file mode 100644
index 000000000000..7726d09cf971
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldHapticsPlayer.kt
@@ -0,0 +1,93 @@
+package com.android.systemui.unfold
+
+import android.os.SystemProperties
+import android.os.VibrationEffect
+import android.os.Vibrator
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import javax.inject.Inject
+
+/**
+ * Class that plays a haptics effect during unfolding a foldable device
+ */
+@SysUIUnfoldScope
+class UnfoldHapticsPlayer
+@Inject
+constructor(
+ unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
+ private val vibrator: Vibrator?
+) : TransitionProgressListener {
+
+ init {
+ if (vibrator != null) {
+ // We don't need to remove the callback because we should listen to it
+ // the whole time when SystemUI process is alive
+ unfoldTransitionProgressProvider.addCallback(this)
+ }
+ }
+
+ private var lastTransitionProgress = TRANSITION_PROGRESS_FULL_OPEN
+
+ override fun onTransitionStarted() {
+ lastTransitionProgress = TRANSITION_PROGRESS_CLOSED
+ }
+
+ override fun onTransitionProgress(progress: Float) {
+ lastTransitionProgress = progress
+ }
+
+ override fun onTransitionFinishing() {
+ // Run haptics only if the animation is long enough to notice
+ if (lastTransitionProgress < TRANSITION_NOTICEABLE_THRESHOLD) {
+ playHaptics()
+ }
+ }
+
+ override fun onTransitionFinished() {
+ lastTransitionProgress = TRANSITION_PROGRESS_FULL_OPEN
+ }
+
+ private fun playHaptics() {
+ vibrator?.vibrate(effect)
+ }
+
+ private val hapticsScale: Float
+ get() {
+ val intensityString = SystemProperties.get("persist.unfold.haptics_scale", "0.1")
+ return intensityString.toFloatOrNull() ?: 0.1f
+ }
+
+ private val hapticsScaleTick: Float
+ get() {
+ val intensityString =
+ SystemProperties.get("persist.unfold.haptics_scale_end_tick", "0.6")
+ return intensityString.toFloatOrNull() ?: 0.6f
+ }
+
+ private val primitivesCount: Int
+ get() {
+ val count = SystemProperties.get("persist.unfold.primitives_count", "18")
+ return count.toIntOrNull() ?: 18
+ }
+
+ private val effect: VibrationEffect by lazy {
+ val composition =
+ VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0F, 0)
+
+ repeat(primitivesCount) {
+ composition.addPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK,
+ hapticsScale,
+ 0
+ )
+ }
+
+ composition
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, hapticsScaleTick)
+ .compose()
+ }
+}
+
+private const val TRANSITION_PROGRESS_CLOSED = 0f
+private const val TRANSITION_PROGRESS_FULL_OPEN = 1f
+private const val TRANSITION_NOTICEABLE_THRESHOLD = 0.9f
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 512fadf1384f..74295f0b8859 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -31,6 +31,7 @@ import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
import android.util.Log
+import com.android.internal.logging.UiEventLogger
import com.android.internal.util.UserIcons
import com.android.systemui.R
import com.android.systemui.SystemUISecondaryUserService
@@ -54,6 +55,7 @@ import com.android.systemui.user.domain.model.ShowDialogRequestModel
import com.android.systemui.user.legacyhelper.data.LegacyUserDataHelper
import com.android.systemui.user.shared.model.UserActionModel
import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.user.utils.MultiUserActionsEvent
import com.android.systemui.util.kotlin.pairwise
import java.io.PrintWriter
import javax.inject.Inject
@@ -93,6 +95,7 @@ constructor(
private val activityManager: ActivityManager,
private val refreshUsersScheduler: RefreshUsersScheduler,
private val guestUserInteractor: GuestUserInteractor,
+ private val uiEventLogger: UiEventLogger,
) {
/**
* Defines interface for classes that can be notified when the state of users on the device is
@@ -115,9 +118,7 @@ constructor(
private val callbackMutex = Mutex()
private val callbacks = mutableSetOf<UserCallback>()
private val userInfos: Flow<List<UserInfo>> =
- repository.userInfos.map { userInfos ->
- userInfos.filter { it.isFull }
- }
+ repository.userInfos.map { userInfos -> userInfos.filter { it.isFull } }
/** List of current on-device users to select from. */
val users: Flow<List<UserModel>>
@@ -427,14 +428,17 @@ constructor(
dialogShower: UserSwitchDialogController.DialogShower? = null,
) {
when (action) {
- UserActionModel.ENTER_GUEST_MODE ->
+ UserActionModel.ENTER_GUEST_MODE -> {
+ uiEventLogger.log(MultiUserActionsEvent.CREATE_GUEST_FROM_USER_SWITCHER)
guestUserInteractor.createAndSwitchTo(
this::showDialog,
this::dismissDialog,
) { userId ->
selectUser(userId, dialogShower)
}
+ }
UserActionModel.ADD_USER -> {
+ uiEventLogger.log(MultiUserActionsEvent.CREATE_USER_FROM_USER_SWITCHER)
val currentUser = repository.getSelectedUserInfo()
showDialog(
ShowDialogRequestModel.ShowAddUserDialog(
@@ -445,7 +449,8 @@ constructor(
)
)
}
- UserActionModel.ADD_SUPERVISED_USER ->
+ UserActionModel.ADD_SUPERVISED_USER -> {
+ uiEventLogger.log(MultiUserActionsEvent.CREATE_RESTRICTED_USER_FROM_USER_SWITCHER)
activityStarter.startActivity(
Intent()
.setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
@@ -453,6 +458,7 @@ constructor(
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
/* dismissShade= */ true,
)
+ }
UserActionModel.NAVIGATE_TO_USER_MANAGEMENT ->
activityStarter.startActivity(
Intent(Settings.ACTION_USER_SETTINGS),
diff --git a/packages/SystemUI/src/com/android/systemui/user/utils/MultiUserActionsEvent.kt b/packages/SystemUI/src/com/android/systemui/user/utils/MultiUserActionsEvent.kt
new file mode 100644
index 000000000000..bfedac9e6f2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/utils/MultiUserActionsEvent.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.user.utils
+
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+
+enum class MultiUserActionsEvent(val value: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Add User tap from User Switcher.") CREATE_USER_FROM_USER_SWITCHER(1257),
+ @UiEvent(doc = "Add Guest tap from User Switcher.") CREATE_GUEST_FROM_USER_SWITCHER(1258),
+ @UiEvent(doc = "Add Restricted User tap from User Switcher.")
+ CREATE_RESTRICTED_USER_FROM_USER_SWITCHER(1259);
+
+ override fun getId(): Int {
+ return value
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 1bc0d08844d7..fa3c73a26f7b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -115,9 +115,11 @@ import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.view.RotationPolicy;
import com.android.settingslib.Utils;
+import com.android.systemui.Dumpable;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.VolumeDialog;
@@ -146,7 +148,7 @@ import java.util.function.Consumer;
*
* Methods ending in "H" must be called on the (ui) handler.
*/
-public class VolumeDialogImpl implements VolumeDialog,
+public class VolumeDialogImpl implements VolumeDialog, Dumpable,
ConfigurationController.ConfigurationListener,
ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = Util.logTag(VolumeDialogImpl.class);
@@ -302,7 +304,8 @@ public class VolumeDialogImpl implements VolumeDialog,
ActivityStarter activityStarter,
InteractionJankMonitor interactionJankMonitor,
DeviceConfigProxy deviceConfigProxy,
- Executor executor) {
+ Executor executor,
+ DumpManager dumpManager) {
mContext =
new ContextThemeWrapper(context, R.style.volume_dialog_theme);
mController = volumeDialogController;
@@ -329,6 +332,8 @@ public class VolumeDialogImpl implements VolumeDialog,
mContext.getResources().getBoolean(R.bool.config_volumeDialogUseBackgroundBlur);
mInteractionJankMonitor = interactionJankMonitor;
+ dumpManager.registerDumpable("VolumeDialogImpl", this);
+
if (mUseBackgroundBlur) {
final int dialogRowsViewColorAboveBlur = mContext.getColor(
R.color.volume_dialog_background_color_above_blur);
@@ -793,7 +798,10 @@ public class VolumeDialogImpl implements VolumeDialog,
return null;
}
- public void dump(PrintWriter writer) {
+ /**
+ * Print dump info for debugging.
+ */
+ public void dump(PrintWriter writer, String[] unusedArgs) {
writer.println(VolumeDialogImpl.class.getSimpleName() + " state:");
writer.print(" mShowing: "); writer.println(mShowing);
writer.print(" mActiveStream: "); writer.println(mActiveStream);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index 8f10fa619c14..0ab6c690e1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -21,6 +21,7 @@ import android.media.AudioManager;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.VolumeDialog;
@@ -61,7 +62,8 @@ public interface VolumeModule {
ActivityStarter activityStarter,
InteractionJankMonitor interactionJankMonitor,
DeviceConfigProxy deviceConfigProxy,
- @Main Executor executor) {
+ @Main Executor executor,
+ DumpManager dumpManager) {
VolumeDialogImpl impl = new VolumeDialogImpl(
context,
volumeDialogController,
@@ -73,7 +75,8 @@ public interface VolumeModule {
activityStarter,
interactionJankMonitor,
deviceConfigProxy,
- executor);
+ executor,
+ dumpManager);
impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
impl.setAutomute(true);
impl.setSilentMode(false);
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index aa4890015977..51742990647d 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -16,8 +16,6 @@
package com.android.systemui.wallpapers;
-import static com.android.systemui.flags.Flags.USE_CANVAS_RENDERER;
-
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.graphics.Bitmap;
@@ -27,17 +25,12 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
-import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.service.wallpaper.WallpaperService;
-import android.util.ArraySet;
import android.util.Log;
-import android.util.MathUtils;
-import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager;
@@ -46,16 +39,10 @@ import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.android.systemui.wallpapers.canvas.WallpaperLocalColorExtractor;
-import com.android.systemui.wallpapers.gl.EglHelper;
-import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@@ -65,33 +52,28 @@ import javax.inject.Inject;
*/
@SuppressWarnings({"UnusedDeclaration"})
public class ImageWallpaper extends WallpaperService {
+
private static final String TAG = ImageWallpaper.class.getSimpleName();
- // We delayed destroy render context that subsequent render requests have chance to cancel it.
- // This is to avoid destroying then recreating render context in a very short time.
- private static final int DELAY_FINISH_RENDERING = 1000;
- private static final @android.annotation.NonNull RectF LOCAL_COLOR_BOUNDS =
- new RectF(0, 0, 1, 1);
private static final boolean DEBUG = false;
- private final ArrayList<RectF> mLocalColorsToAdd = new ArrayList<>();
- private final ArraySet<RectF> mColorAreas = new ArraySet<>();
+ // keep track of the number of pages of the launcher for local color extraction purposes
private volatile int mPages = 1;
private boolean mPagesComputed = false;
+
+ // used to handle WallpaperService messages (e.g. DO_ATTACH, MSG_UPDATE_SURFACE)
+ // and to receive WallpaperService callbacks (e.g. onCreateEngine, onSurfaceRedrawNeeded)
private HandlerThread mWorker;
- // scaled down version
- private Bitmap mMiniBitmap;
- private final FeatureFlags mFeatureFlags;
- // used in canvasEngine to load/unload the bitmap and extract the colors
+ // used for most tasks (call canvas.drawBitmap, load/unload the bitmap)
@Background
private final DelayableExecutor mBackgroundExecutor;
+
+ // wait at least this duration before unloading the bitmap
private static final int DELAY_UNLOAD_BITMAP = 2000;
@Inject
- public ImageWallpaper(FeatureFlags featureFlags,
- @Background DelayableExecutor backgroundExecutor) {
+ public ImageWallpaper(@Background DelayableExecutor backgroundExecutor) {
super();
- mFeatureFlags = featureFlags;
mBackgroundExecutor = backgroundExecutor;
}
@@ -113,416 +95,9 @@ public class ImageWallpaper extends WallpaperService {
@Override
public Engine onCreateEngine() {
- return mFeatureFlags.isEnabled(USE_CANVAS_RENDERER) ? new CanvasEngine() : new GLEngine();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mWorker.quitSafely();
- mWorker = null;
- mMiniBitmap = null;
+ return new CanvasEngine();
}
- class GLEngine extends Engine implements DisplayListener {
- // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin)
- // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail.
- @VisibleForTesting
- static final int MIN_SURFACE_WIDTH = 128;
- @VisibleForTesting
- static final int MIN_SURFACE_HEIGHT = 128;
-
- private ImageWallpaperRenderer mRenderer;
- private EglHelper mEglHelper;
- private final Runnable mFinishRenderingTask = this::finishRendering;
- private boolean mNeedRedraw;
-
- private boolean mDisplaySizeValid = false;
- private int mDisplayWidth = 1;
- private int mDisplayHeight = 1;
-
- private int mImgWidth = 1;
- private int mImgHeight = 1;
-
- GLEngine() { }
-
- @VisibleForTesting
- GLEngine(Handler handler) {
- super(SystemClock::elapsedRealtime, handler);
- }
-
- @Override
- public void onCreate(SurfaceHolder surfaceHolder) {
- Trace.beginSection("ImageWallpaper.Engine#onCreate");
- mEglHelper = getEglHelperInstance();
- // Deferred init renderer because we need to get wallpaper by display context.
- mRenderer = getRendererInstance();
- setFixedSizeAllowed(true);
- updateSurfaceSize();
- setShowForAllUsers(true);
-
- mRenderer.setOnBitmapChanged(b -> {
- mLocalColorsToAdd.addAll(mColorAreas);
- if (mLocalColorsToAdd.size() > 0) {
- updateMiniBitmapAndNotify(b);
- }
- });
- getDisplayContext().getSystemService(DisplayManager.class)
- .registerDisplayListener(this, mWorker.getThreadHandler());
- Trace.endSection();
- }
-
- @Override
- public void onDisplayAdded(int displayId) { }
-
- @Override
- public void onDisplayRemoved(int displayId) { }
-
- @Override
- public void onDisplayChanged(int displayId) {
- if (displayId == getDisplayContext().getDisplayId()) {
- mDisplaySizeValid = false;
- }
- }
-
- EglHelper getEglHelperInstance() {
- return new EglHelper();
- }
-
- ImageWallpaperRenderer getRendererInstance() {
- return new ImageWallpaperRenderer(getDisplayContext());
- }
-
- @Override
- public void onOffsetsChanged(float xOffset, float yOffset,
- float xOffsetStep, float yOffsetStep,
- int xPixelOffset, int yPixelOffset) {
- final int pages;
- if (xOffsetStep > 0 && xOffsetStep <= 1) {
- pages = (int) Math.round(1 / xOffsetStep) + 1;
- } else {
- pages = 1;
- }
- if (pages == mPages) return;
- mPages = pages;
- if (mMiniBitmap == null || mMiniBitmap.isRecycled()) return;
- mWorker.getThreadHandler().post(() ->
- computeAndNotifyLocalColors(new ArrayList<>(mColorAreas), mMiniBitmap));
- }
-
- private void updateMiniBitmapAndNotify(Bitmap b) {
- if (b == null) return;
- int size = Math.min(b.getWidth(), b.getHeight());
- float scale = 1.0f;
- if (size > MIN_SURFACE_WIDTH) {
- scale = (float) MIN_SURFACE_WIDTH / (float) size;
- }
- mImgHeight = b.getHeight();
- mImgWidth = b.getWidth();
- mMiniBitmap = Bitmap.createScaledBitmap(b, (int) Math.max(scale * b.getWidth(), 1),
- (int) Math.max(scale * b.getHeight(), 1), false);
- computeAndNotifyLocalColors(mLocalColorsToAdd, mMiniBitmap);
- mLocalColorsToAdd.clear();
- }
-
- private void updateSurfaceSize() {
- Trace.beginSection("ImageWallpaper#updateSurfaceSize");
- SurfaceHolder holder = getSurfaceHolder();
- Size frameSize = mRenderer.reportSurfaceSize();
- int width = Math.max(MIN_SURFACE_WIDTH, frameSize.getWidth());
- int height = Math.max(MIN_SURFACE_HEIGHT, frameSize.getHeight());
- holder.setFixedSize(width, height);
- Trace.endSection();
- }
-
- @Override
- public boolean shouldZoomOutWallpaper() {
- return true;
- }
-
- @Override
- public boolean shouldWaitForEngineShown() {
- return true;
- }
-
- @Override
- public void onDestroy() {
- getDisplayContext().getSystemService(DisplayManager.class)
- .unregisterDisplayListener(this);
- mMiniBitmap = null;
- mWorker.getThreadHandler().post(() -> {
- mRenderer.finish();
- mRenderer = null;
- mEglHelper.finish();
- mEglHelper = null;
- });
- }
-
- @Override
- public boolean supportsLocalColorExtraction() {
- return true;
- }
-
- @Override
- public void addLocalColorsAreas(@NonNull List<RectF> regions) {
- mWorker.getThreadHandler().post(() -> {
- if (mColorAreas.size() + mLocalColorsToAdd.size() == 0) {
- setOffsetNotificationsEnabled(true);
- }
- Bitmap bitmap = mMiniBitmap;
- if (bitmap == null) {
- mLocalColorsToAdd.addAll(regions);
- if (mRenderer != null) mRenderer.use(this::updateMiniBitmapAndNotify);
- } else {
- computeAndNotifyLocalColors(regions, bitmap);
- }
- });
- }
-
- private void computeAndNotifyLocalColors(@NonNull List<RectF> regions, Bitmap b) {
- List<WallpaperColors> colors = getLocalWallpaperColors(regions, b);
- mColorAreas.addAll(regions);
- try {
- notifyLocalColorsChanged(regions, colors);
- } catch (RuntimeException e) {
- Log.e(TAG, e.getMessage(), e);
- }
- }
-
- @Override
- public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
- mWorker.getThreadHandler().post(() -> {
- mColorAreas.removeAll(regions);
- mLocalColorsToAdd.removeAll(regions);
- if (mColorAreas.size() + mLocalColorsToAdd.size() == 0) {
- setOffsetNotificationsEnabled(false);
- }
- });
- }
-
- /**
- * Transform the logical coordinates into wallpaper coordinates.
- *
- * Logical coordinates are organised such that the various pages are non-overlapping. So,
- * if there are n pages, the first page will have its X coordinate on the range [0-1/n].
- *
- * The real pages are overlapping. If the Wallpaper are a width Ww and the screen a width
- * Ws, the relative width of a page Wr is Ws/Ww. This does not change if the number of
- * pages increase.
- * If there are n pages, the page k starts at the offset k * (1 - Wr) / (n - 1), as the
- * last page is at position (1-Wr) and the others are regularly spread on the range [0-
- * (1-Wr)].
- */
- private RectF pageToImgRect(RectF area) {
- if (!mDisplaySizeValid) {
- Rect window = getDisplayContext()
- .getSystemService(WindowManager.class)
- .getCurrentWindowMetrics()
- .getBounds();
- mDisplayWidth = window.width();
- mDisplayHeight = window.height();
- mDisplaySizeValid = true;
- }
-
- // Width of a page for the caller of this API.
- float virtualPageWidth = 1f / (float) mPages;
- float leftPosOnPage = (area.left % virtualPageWidth) / virtualPageWidth;
- float rightPosOnPage = (area.right % virtualPageWidth) / virtualPageWidth;
- int currentPage = (int) Math.floor(area.centerX() / virtualPageWidth);
-
- RectF imgArea = new RectF();
-
- if (mImgWidth == 0 || mImgHeight == 0 || mDisplayWidth <= 0 || mDisplayHeight <= 0) {
- return imgArea;
- }
-
- imgArea.bottom = area.bottom;
- imgArea.top = area.top;
-
- float imageScale = Math.min(((float) mImgHeight) / mDisplayHeight, 1);
- float mappedScreenWidth = mDisplayWidth * imageScale;
- float pageWidth = Math.min(1.0f,
- mImgWidth > 0 ? mappedScreenWidth / (float) mImgWidth : 1.f);
- float pageOffset = (1 - pageWidth) / (float) (mPages - 1);
-
- imgArea.left = MathUtils.constrain(
- leftPosOnPage * pageWidth + currentPage * pageOffset, 0, 1);
- imgArea.right = MathUtils.constrain(
- rightPosOnPage * pageWidth + currentPage * pageOffset, 0, 1);
- if (imgArea.left > imgArea.right) {
- // take full page
- imgArea.left = 0;
- imgArea.right = 1;
- }
- return imgArea;
- }
-
- private List<WallpaperColors> getLocalWallpaperColors(@NonNull List<RectF> areas,
- Bitmap b) {
- List<WallpaperColors> colors = new ArrayList<>(areas.size());
- for (int i = 0; i < areas.size(); i++) {
- RectF area = pageToImgRect(areas.get(i));
- if (area == null || !LOCAL_COLOR_BOUNDS.contains(area)) {
- colors.add(null);
- continue;
- }
- Rect subImage = new Rect(
- (int) Math.floor(area.left * b.getWidth()),
- (int) Math.floor(area.top * b.getHeight()),
- (int) Math.ceil(area.right * b.getWidth()),
- (int) Math.ceil(area.bottom * b.getHeight()));
- if (subImage.isEmpty()) {
- // Do not notify client. treat it as too small to sample
- colors.add(null);
- continue;
- }
- Bitmap colorImg = Bitmap.createBitmap(b,
- subImage.left, subImage.top, subImage.width(), subImage.height());
- WallpaperColors color = WallpaperColors.fromBitmap(colorImg);
- colors.add(color);
- }
- return colors;
- }
-
- @Override
- public void onSurfaceCreated(SurfaceHolder holder) {
- if (mWorker == null) return;
- mWorker.getThreadHandler().post(() -> {
- Trace.beginSection("ImageWallpaper#onSurfaceCreated");
- mEglHelper.init(holder, needSupportWideColorGamut());
- mRenderer.onSurfaceCreated();
- Trace.endSection();
- });
- }
-
- @Override
- public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- if (mWorker == null) return;
- mWorker.getThreadHandler().post(() -> mRenderer.onSurfaceChanged(width, height));
- }
-
- @Override
- public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
- if (mWorker == null) return;
- mWorker.getThreadHandler().post(this::drawFrame);
- }
-
- private void drawFrame() {
- Trace.beginSection("ImageWallpaper#drawFrame");
- preRender();
- requestRender();
- postRender();
- Trace.endSection();
- }
-
- public void preRender() {
- // This method should only be invoked from worker thread.
- Trace.beginSection("ImageWallpaper#preRender");
- preRenderInternal();
- Trace.endSection();
- }
-
- private void preRenderInternal() {
- boolean contextRecreated = false;
- Rect frame = getSurfaceHolder().getSurfaceFrame();
- cancelFinishRenderingTask();
-
- // Check if we need to recreate egl context.
- if (!mEglHelper.hasEglContext()) {
- mEglHelper.destroyEglSurface();
- if (!mEglHelper.createEglContext()) {
- Log.w(TAG, "recreate egl context failed!");
- } else {
- contextRecreated = true;
- }
- }
-
- // Check if we need to recreate egl surface.
- if (mEglHelper.hasEglContext() && !mEglHelper.hasEglSurface()) {
- if (!mEglHelper.createEglSurface(getSurfaceHolder(), needSupportWideColorGamut())) {
- Log.w(TAG, "recreate egl surface failed!");
- }
- }
-
- // If we recreate egl context, notify renderer to setup again.
- if (mEglHelper.hasEglContext() && mEglHelper.hasEglSurface() && contextRecreated) {
- mRenderer.onSurfaceCreated();
- mRenderer.onSurfaceChanged(frame.width(), frame.height());
- }
- }
-
- public void requestRender() {
- // This method should only be invoked from worker thread.
- Trace.beginSection("ImageWallpaper#requestRender");
- requestRenderInternal();
- Trace.endSection();
- }
-
- private void requestRenderInternal() {
- Rect frame = getSurfaceHolder().getSurfaceFrame();
- boolean readyToRender = mEglHelper.hasEglContext() && mEglHelper.hasEglSurface()
- && frame.width() > 0 && frame.height() > 0;
-
- if (readyToRender) {
- mRenderer.onDrawFrame();
- if (!mEglHelper.swapBuffer()) {
- Log.e(TAG, "drawFrame failed!");
- }
- } else {
- Log.e(TAG, "requestRender: not ready, has context=" + mEglHelper.hasEglContext()
- + ", has surface=" + mEglHelper.hasEglSurface()
- + ", frame=" + frame);
- }
- }
-
- public void postRender() {
- // This method should only be invoked from worker thread.
- scheduleFinishRendering();
- reportEngineShown(false /* waitForEngineShown */);
- }
-
- private void cancelFinishRenderingTask() {
- if (mWorker == null) return;
- mWorker.getThreadHandler().removeCallbacks(mFinishRenderingTask);
- }
-
- private void scheduleFinishRendering() {
- if (mWorker == null) return;
- cancelFinishRenderingTask();
- mWorker.getThreadHandler().postDelayed(mFinishRenderingTask, DELAY_FINISH_RENDERING);
- }
-
- private void finishRendering() {
- Trace.beginSection("ImageWallpaper#finishRendering");
- if (mEglHelper != null) {
- mEglHelper.destroyEglSurface();
- mEglHelper.destroyEglContext();
- }
- Trace.endSection();
- }
-
- private boolean needSupportWideColorGamut() {
- return mRenderer.isWcgContent();
- }
-
- @Override
- protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
- super.dump(prefix, fd, out, args);
- out.print(prefix); out.print("Engine="); out.println(this);
- out.print(prefix); out.print("valid surface=");
- out.println(getSurfaceHolder() != null && getSurfaceHolder().getSurface() != null
- ? getSurfaceHolder().getSurface().isValid()
- : "null");
-
- out.print(prefix); out.print("surface frame=");
- out.println(getSurfaceHolder() != null ? getSurfaceHolder().getSurfaceFrame() : "null");
-
- mEglHelper.dump(prefix, fd, out, args);
- mRenderer.dump(prefix, fd, out, args);
- }
- }
-
-
class CanvasEngine extends WallpaperService.Engine implements DisplayListener {
private WallpaperManager mWallpaperManager;
private final WallpaperLocalColorExtractor mWallpaperLocalColorExtractor;
@@ -746,13 +321,8 @@ public class ImageWallpaper extends WallpaperService {
// be loaded, we will go into a cycle. Don't do a build where the
// default wallpaper can't be loaded.
Log.w(TAG, "Unable to load wallpaper!", exception);
- try {
- mWallpaperManager.clear(WallpaperManager.FLAG_SYSTEM);
- } catch (IOException ex) {
- // now we're really screwed.
- Log.w(TAG, "Unable reset to default wallpaper!", ex);
- }
-
+ mWallpaperManager.clearWallpaper(
+ WallpaperManager.FLAG_SYSTEM, UserHandle.USER_CURRENT);
try {
bitmap = mWallpaperManager.getBitmapAsUser(UserHandle.USER_CURRENT, false);
} catch (RuntimeException | OutOfMemoryError e) {
@@ -878,7 +448,6 @@ public class ImageWallpaper extends WallpaperService {
mWallpaperLocalColorExtractor.setDisplayDimensions(window.width(), window.height());
}
-
@Override
protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
super.dump(prefix, fd, out, args);
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/WallpaperLocalColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
index 6cac5c952b7c..988fd710d2dc 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/WallpaperLocalColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
@@ -15,7 +15,7 @@
*/
-package com.android.systemui.wallpapers.canvas;
+package com.android.systemui.wallpapers;
import android.app.WallpaperColors;
import android.graphics.Bitmap;
@@ -31,7 +31,6 @@ import androidx.annotation.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.util.Assert;
-import com.android.systemui.wallpapers.ImageWallpaper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
deleted file mode 100644
index f9ddce8e3b2e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.wallpapers.gl;
-
-import static android.opengl.EGL14.EGL_ALPHA_SIZE;
-import static android.opengl.EGL14.EGL_BLUE_SIZE;
-import static android.opengl.EGL14.EGL_CONFIG_CAVEAT;
-import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
-import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
-import static android.opengl.EGL14.EGL_DEPTH_SIZE;
-import static android.opengl.EGL14.EGL_EXTENSIONS;
-import static android.opengl.EGL14.EGL_GREEN_SIZE;
-import static android.opengl.EGL14.EGL_NONE;
-import static android.opengl.EGL14.EGL_NO_CONTEXT;
-import static android.opengl.EGL14.EGL_NO_DISPLAY;
-import static android.opengl.EGL14.EGL_NO_SURFACE;
-import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
-import static android.opengl.EGL14.EGL_RED_SIZE;
-import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
-import static android.opengl.EGL14.EGL_STENCIL_SIZE;
-import static android.opengl.EGL14.EGL_SUCCESS;
-import static android.opengl.EGL14.eglChooseConfig;
-import static android.opengl.EGL14.eglCreateContext;
-import static android.opengl.EGL14.eglCreateWindowSurface;
-import static android.opengl.EGL14.eglDestroyContext;
-import static android.opengl.EGL14.eglDestroySurface;
-import static android.opengl.EGL14.eglGetDisplay;
-import static android.opengl.EGL14.eglGetError;
-import static android.opengl.EGL14.eglInitialize;
-import static android.opengl.EGL14.eglMakeCurrent;
-import static android.opengl.EGL14.eglQueryString;
-import static android.opengl.EGL14.eglSwapBuffers;
-import static android.opengl.EGL14.eglTerminate;
-
-import android.opengl.EGLConfig;
-import android.opengl.EGLContext;
-import android.opengl.EGLDisplay;
-import android.opengl.EGLSurface;
-import android.opengl.GLUtils;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.SurfaceHolder;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A helper class to handle EGL management.
- */
-public class EglHelper {
- private static final String TAG = EglHelper.class.getSimpleName();
- private static final int OPENGLES_VERSION = 2;
- // Below two constants make drawing at low priority, so other things can preempt our drawing.
- private static final int EGL_CONTEXT_PRIORITY_LEVEL_IMG = 0x3100;
- private static final int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
- private static final boolean DEBUG = true;
-
- private static final int EGL_GL_COLORSPACE_KHR = 0x309D;
- private static final int EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
-
- private static final String EGL_IMG_CONTEXT_PRIORITY = "EGL_IMG_context_priority";
-
- /**
- * https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_gl_colorspace.txt
- */
- private static final String KHR_GL_COLOR_SPACE = "EGL_KHR_gl_colorspace";
-
- /**
- * https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_gl_colorspace_display_p3_passthrough.txt
- */
- private static final String EXT_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH =
- "EGL_EXT_gl_colorspace_display_p3_passthrough";
-
- private EGLDisplay mEglDisplay;
- private EGLConfig mEglConfig;
- private EGLContext mEglContext;
- private EGLSurface mEglSurface;
- private final int[] mEglVersion = new int[2];
- private boolean mEglReady;
- private final Set<String> mExts;
-
- public EglHelper() {
- mExts = new HashSet<>();
- connectDisplay();
- }
-
- /**
- * Initialize render context.
- * @param surfaceHolder surface holder.
- * @param wideColorGamut claim if a wcg surface is necessary.
- * @return true if the render context is ready.
- */
- public boolean init(SurfaceHolder surfaceHolder, boolean wideColorGamut) {
- if (!hasEglDisplay() && !connectDisplay()) {
- Log.w(TAG, "Can not connect display, abort!");
- return false;
- }
-
- if (!eglInitialize(mEglDisplay, mEglVersion, 0 /* majorOffset */,
- mEglVersion, 1 /* minorOffset */)) {
- Log.w(TAG, "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError()));
- return false;
- }
-
- mEglConfig = chooseEglConfig();
- if (mEglConfig == null) {
- Log.w(TAG, "eglConfig not initialized!");
- return false;
- }
-
- if (!createEglContext()) {
- Log.w(TAG, "Can't create EGLContext!");
- return false;
- }
-
- if (!createEglSurface(surfaceHolder, wideColorGamut)) {
- Log.w(TAG, "Can't create EGLSurface!");
- return false;
- }
-
- mEglReady = true;
- return true;
- }
-
- private boolean connectDisplay() {
- mExts.clear();
- mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (!hasEglDisplay()) {
- Log.w(TAG, "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError()));
- return false;
- }
- String queryString = eglQueryString(mEglDisplay, EGL_EXTENSIONS);
- if (!TextUtils.isEmpty(queryString)) {
- Collections.addAll(mExts, queryString.split(" "));
- }
- return true;
- }
-
- boolean checkExtensionCapability(String extName) {
- return mExts.contains(extName);
- }
-
- int getWcgCapability() {
- if (checkExtensionCapability(EXT_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH)) {
- return EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
- }
- return 0;
- }
-
- private EGLConfig chooseEglConfig() {
- int[] configsCount = new int[1];
- EGLConfig[] configs = new EGLConfig[1];
- int[] configSpec = getConfig();
- if (!eglChooseConfig(mEglDisplay, configSpec, 0, configs, 0, 1, configsCount, 0)) {
- Log.w(TAG, "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError()));
- return null;
- } else {
- if (configsCount[0] <= 0) {
- Log.w(TAG, "eglChooseConfig failed, invalid configs count: " + configsCount[0]);
- return null;
- } else {
- return configs[0];
- }
- }
- }
-
- private int[] getConfig() {
- return new int[] {
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 0,
- EGL_DEPTH_SIZE, 0,
- EGL_STENCIL_SIZE, 0,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_CONFIG_CAVEAT, EGL_NONE,
- EGL_NONE
- };
- }
-
- /**
- * Prepare an EglSurface.
- * @param surfaceHolder surface holder.
- * @param wcg if need to support wcg.
- * @return true if EglSurface is ready.
- */
- public boolean createEglSurface(SurfaceHolder surfaceHolder, boolean wcg) {
- if (DEBUG) {
- Log.d(TAG, "createEglSurface start");
- }
-
- if (hasEglDisplay() && surfaceHolder.getSurface().isValid()) {
- int[] attrs = null;
- int wcgCapability = getWcgCapability();
- if (wcg && checkExtensionCapability(KHR_GL_COLOR_SPACE) && wcgCapability > 0) {
- attrs = new int[] {EGL_GL_COLORSPACE_KHR, wcgCapability, EGL_NONE};
- }
- mEglSurface = askCreatingEglWindowSurface(surfaceHolder, attrs, 0 /* offset */);
- } else {
- Log.w(TAG, "Create EglSurface failed: hasEglDisplay=" + hasEglDisplay()
- + ", has valid surface=" + surfaceHolder.getSurface().isValid());
- return false;
- }
-
- if (!hasEglSurface()) {
- Log.w(TAG, "createWindowSurface failed: " + GLUtils.getEGLErrorString(eglGetError()));
- return false;
- }
-
- if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- Log.w(TAG, "eglMakeCurrent failed: " + GLUtils.getEGLErrorString(eglGetError()));
- return false;
- }
-
- if (DEBUG) {
- Log.d(TAG, "createEglSurface done");
- }
- return true;
- }
-
- EGLSurface askCreatingEglWindowSurface(SurfaceHolder holder, int[] attrs, int offset) {
- return eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, attrs, offset);
- }
-
- /**
- * Destroy EglSurface.
- */
- public void destroyEglSurface() {
- if (hasEglSurface()) {
- eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(mEglDisplay, mEglSurface);
- mEglSurface = EGL_NO_SURFACE;
- }
- }
-
- /**
- * Check if we have a valid EglSurface.
- * @return true if EglSurface is ready.
- */
- public boolean hasEglSurface() {
- return mEglSurface != null && mEglSurface != EGL_NO_SURFACE;
- }
-
- /**
- * Prepare EglContext.
- * @return true if EglContext is ready.
- */
- public boolean createEglContext() {
- if (DEBUG) {
- Log.d(TAG, "createEglContext start");
- }
-
- int[] attrib_list = new int[5];
- int idx = 0;
- attrib_list[idx++] = EGL_CONTEXT_CLIENT_VERSION;
- attrib_list[idx++] = OPENGLES_VERSION;
- if (checkExtensionCapability(EGL_IMG_CONTEXT_PRIORITY)) {
- attrib_list[idx++] = EGL_CONTEXT_PRIORITY_LEVEL_IMG;
- attrib_list[idx++] = EGL_CONTEXT_PRIORITY_LOW_IMG;
- }
- attrib_list[idx] = EGL_NONE;
- if (hasEglDisplay()) {
- mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0);
- } else {
- Log.w(TAG, "mEglDisplay is null");
- return false;
- }
-
- if (!hasEglContext()) {
- Log.w(TAG, "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()));
- return false;
- }
-
- if (DEBUG) {
- Log.d(TAG, "createEglContext done");
- }
- return true;
- }
-
- /**
- * Destroy EglContext.
- */
- public void destroyEglContext() {
- if (hasEglContext()) {
- eglDestroyContext(mEglDisplay, mEglContext);
- mEglContext = EGL_NO_CONTEXT;
- }
- }
-
- /**
- * Check if we have EglContext.
- * @return true if EglContext is ready.
- */
- public boolean hasEglContext() {
- return mEglContext != null && mEglContext != EGL_NO_CONTEXT;
- }
-
- /**
- * Check if we have EglDisplay.
- * @return true if EglDisplay is ready.
- */
- public boolean hasEglDisplay() {
- return mEglDisplay != null && mEglDisplay != EGL_NO_DISPLAY;
- }
-
- /**
- * Swap buffer to display.
- * @return true if swap successfully.
- */
- public boolean swapBuffer() {
- boolean status = eglSwapBuffers(mEglDisplay, mEglSurface);
- int error = eglGetError();
- if (error != EGL_SUCCESS) {
- Log.w(TAG, "eglSwapBuffers failed: " + GLUtils.getEGLErrorString(error));
- }
- return status;
- }
-
- /**
- * Destroy EglSurface and EglContext, then terminate EGL.
- */
- public void finish() {
- if (hasEglSurface()) {
- destroyEglSurface();
- }
- if (hasEglContext()) {
- destroyEglContext();
- }
- if (hasEglDisplay()) {
- terminateEglDisplay();
- }
- mEglReady = false;
- }
-
- void terminateEglDisplay() {
- eglTerminate(mEglDisplay);
- mEglDisplay = EGL_NO_DISPLAY;
- }
-
- /**
- * Called to dump current state.
- * @param prefix prefix.
- * @param fd fd.
- * @param out out.
- * @param args args.
- */
- public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
- String eglVersion = mEglVersion[0] + "." + mEglVersion[1];
- out.print(prefix); out.print("EGL version="); out.print(eglVersion);
- out.print(", "); out.print("EGL ready="); out.print(mEglReady);
- out.print(", "); out.print("has EglContext="); out.print(hasEglContext());
- out.print(", "); out.print("has EglSurface="); out.println(hasEglSurface());
-
- int[] configs = getConfig();
- StringBuilder sb = new StringBuilder();
- sb.append('{');
- for (int egl : configs) {
- sb.append("0x").append(Integer.toHexString(egl)).append(",");
- }
- sb.setCharAt(sb.length() - 1, '}');
- out.print(prefix); out.print("EglConfig="); out.println(sb.toString());
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
deleted file mode 100644
index 692ced08f613..000000000000
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.wallpapers.gl;
-
-import android.util.Size;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * A renderer which is responsible for making OpenGL calls to render a frame.
- */
-public interface GLWallpaperRenderer {
-
- /**
- * Check if the content to render is a WCG content.
- */
- boolean isWcgContent();
-
- /**
- * Called when the surface is created or recreated.
- */
- void onSurfaceCreated();
-
- /**
- * Called when the surface changed size.
- * @param width surface width.
- * @param height surface height.
- */
- void onSurfaceChanged(int width, int height);
-
- /**
- * Called to draw the current frame.
- */
- void onDrawFrame();
-
- /**
- * Ask renderer to report the surface size it needs.
- */
- Size reportSurfaceSize();
-
- /**
- * Called when no need to render any more.
- */
- void finish();
-
- /**
- * Called to dump current state.
- * @param prefix prefix.
- * @param fd fd.
- * @param out out.
- * @param args args.
- */
- void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args);
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
deleted file mode 100644
index d34eca4831db..000000000000
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.wallpapers.gl;
-
-import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
-import static android.opengl.GLES20.GL_VERTEX_SHADER;
-import static android.opengl.GLES20.glAttachShader;
-import static android.opengl.GLES20.glCompileShader;
-import static android.opengl.GLES20.glCreateProgram;
-import static android.opengl.GLES20.glCreateShader;
-import static android.opengl.GLES20.glGetAttribLocation;
-import static android.opengl.GLES20.glGetUniformLocation;
-import static android.opengl.GLES20.glLinkProgram;
-import static android.opengl.GLES20.glShaderSource;
-import static android.opengl.GLES20.glUseProgram;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/**
- * This class takes charge of linking shader codes and then return a handle for OpenGL ES program.
- */
-class ImageGLProgram {
- private static final String TAG = ImageGLProgram.class.getSimpleName();
-
- private Context mContext;
- private int mProgramHandle;
-
- ImageGLProgram(Context context) {
- mContext = context.getApplicationContext();
- }
-
- private int loadShaderProgram(int vertexId, int fragmentId) {
- final String vertexSrc = getShaderResource(vertexId);
- final String fragmentSrc = getShaderResource(fragmentId);
- final int vertexHandle = getShaderHandle(GL_VERTEX_SHADER, vertexSrc);
- final int fragmentHandle = getShaderHandle(GL_FRAGMENT_SHADER, fragmentSrc);
- return getProgramHandle(vertexHandle, fragmentHandle);
- }
-
- private String getShaderResource(int shaderId) {
- Resources res = mContext.getResources();
- StringBuilder code = new StringBuilder();
-
- try (BufferedReader reader = new BufferedReader(
- new InputStreamReader(res.openRawResource(shaderId)))) {
- String nextLine;
- while ((nextLine = reader.readLine()) != null) {
- code.append(nextLine).append("\n");
- }
- } catch (IOException | Resources.NotFoundException ex) {
- Log.d(TAG, "Can not read the shader source", ex);
- code = null;
- }
-
- return code == null ? "" : code.toString();
- }
-
- private int getShaderHandle(int type, String src) {
- final int shader = glCreateShader(type);
- if (shader == 0) {
- Log.d(TAG, "Create shader failed, type=" + type);
- return 0;
- }
- glShaderSource(shader, src);
- glCompileShader(shader);
- return shader;
- }
-
- private int getProgramHandle(int vertexHandle, int fragmentHandle) {
- final int program = glCreateProgram();
- if (program == 0) {
- Log.d(TAG, "Can not create OpenGL ES program");
- return 0;
- }
-
- glAttachShader(program, vertexHandle);
- glAttachShader(program, fragmentHandle);
- glLinkProgram(program);
- return program;
- }
-
- boolean useGLProgram(int vertexResId, int fragmentResId) {
- mProgramHandle = loadShaderProgram(vertexResId, fragmentResId);
- glUseProgram(mProgramHandle);
- return true;
- }
-
- int getAttributeHandle(String name) {
- return glGetAttribLocation(mProgramHandle, name);
- }
-
- int getUniformHandle(String name) {
- return glGetUniformLocation(mProgramHandle, name);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
deleted file mode 100644
index f1659b9a8723..000000000000
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.wallpapers.gl;
-
-import static android.opengl.GLES20.GL_FLOAT;
-import static android.opengl.GLES20.GL_LINEAR;
-import static android.opengl.GLES20.GL_TEXTURE0;
-import static android.opengl.GLES20.GL_TEXTURE_2D;
-import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
-import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
-import static android.opengl.GLES20.GL_TRIANGLES;
-import static android.opengl.GLES20.glActiveTexture;
-import static android.opengl.GLES20.glBindTexture;
-import static android.opengl.GLES20.glDrawArrays;
-import static android.opengl.GLES20.glEnableVertexAttribArray;
-import static android.opengl.GLES20.glGenTextures;
-import static android.opengl.GLES20.glTexParameteri;
-import static android.opengl.GLES20.glUniform1i;
-import static android.opengl.GLES20.glVertexAttribPointer;
-
-import android.graphics.Bitmap;
-import android.opengl.GLUtils;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-
-/**
- * This class takes charge of the geometry data like vertices and texture coordinates.
- * It delivers these data to opengl runtime and triggers draw calls if necessary.
- */
-class ImageGLWallpaper {
- private static final String TAG = ImageGLWallpaper.class.getSimpleName();
-
- private static final String A_POSITION = "aPosition";
- private static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
- private static final String U_TEXTURE = "uTexture";
- private static final int POSITION_COMPONENT_COUNT = 2;
- private static final int TEXTURE_COMPONENT_COUNT = 2;
- private static final int BYTES_PER_FLOAT = 4;
-
- // Vertices to define the square with 2 triangles.
- private static final float[] VERTICES = {
- -1.0f, -1.0f,
- +1.0f, -1.0f,
- +1.0f, +1.0f,
- +1.0f, +1.0f,
- -1.0f, +1.0f,
- -1.0f, -1.0f
- };
-
- // Texture coordinates that maps to vertices.
- private static final float[] TEXTURES = {
- 0f, 1f,
- 1f, 1f,
- 1f, 0f,
- 1f, 0f,
- 0f, 0f,
- 0f, 1f
- };
-
- private final FloatBuffer mVertexBuffer;
- private final FloatBuffer mTextureBuffer;
- private final ImageGLProgram mProgram;
-
- private int mAttrPosition;
- private int mAttrTextureCoordinates;
- private int mUniTexture;
- private int mTextureId;
-
- ImageGLWallpaper(ImageGLProgram program) {
- mProgram = program;
-
- // Create an float array in opengles runtime (native) and put vertex data.
- mVertexBuffer = ByteBuffer.allocateDirect(VERTICES.length * BYTES_PER_FLOAT)
- .order(ByteOrder.nativeOrder())
- .asFloatBuffer();
- mVertexBuffer.put(VERTICES);
- mVertexBuffer.position(0);
-
- // Create an float array in opengles runtime (native) and put texture data.
- mTextureBuffer = ByteBuffer.allocateDirect(TEXTURES.length * BYTES_PER_FLOAT)
- .order(ByteOrder.nativeOrder())
- .asFloatBuffer();
- mTextureBuffer.put(TEXTURES);
- mTextureBuffer.position(0);
- }
-
- void setup(Bitmap bitmap) {
- setupAttributes();
- setupUniforms();
- setupTexture(bitmap);
- }
-
- private void setupAttributes() {
- mAttrPosition = mProgram.getAttributeHandle(A_POSITION);
- mVertexBuffer.position(0);
- glVertexAttribPointer(mAttrPosition, POSITION_COMPONENT_COUNT, GL_FLOAT,
- false, 0, mVertexBuffer);
- glEnableVertexAttribArray(mAttrPosition);
-
- mAttrTextureCoordinates = mProgram.getAttributeHandle(A_TEXTURE_COORDINATES);
- mTextureBuffer.position(0);
- glVertexAttribPointer(mAttrTextureCoordinates, TEXTURE_COMPONENT_COUNT, GL_FLOAT,
- false, 0, mTextureBuffer);
- glEnableVertexAttribArray(mAttrTextureCoordinates);
- }
-
- private void setupUniforms() {
- mUniTexture = mProgram.getUniformHandle(U_TEXTURE);
- }
-
- void draw() {
- glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
- }
-
- private void setupTexture(Bitmap bitmap) {
- final int[] tids = new int[1];
-
- if (bitmap == null || bitmap.isRecycled()) {
- Log.w(TAG, "setupTexture: invalid bitmap");
- return;
- }
-
- // Generate one texture object and store the id in tids[0].
- glGenTextures(1, tids, 0);
- if (tids[0] == 0) {
- Log.w(TAG, "setupTexture: glGenTextures() failed");
- return;
- }
-
- try {
- // Bind a named texture to a target.
- glBindTexture(GL_TEXTURE_2D, tids[0]);
- // Load the bitmap data and copy it over into the texture object
- // that is currently bound.
- GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
- // Use bilinear texture filtering when minification.
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- // Use bilinear texture filtering when magnification.
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- mTextureId = tids[0];
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Failed uploading texture: " + e.getLocalizedMessage());
- }
- }
-
- void useTexture() {
- // Set the active texture unit to texture unit 0.
- glActiveTexture(GL_TEXTURE0);
- // Bind the texture to this unit.
- glBindTexture(GL_TEXTURE_2D, mTextureId);
- // Let the texture sampler in fragment shader to read form this texture unit.
- glUniform1i(mUniTexture, 0);
- }
-
- /**
- * Called to dump current state.
- * @param prefix prefix.
- * @param fd fd.
- * @param out out.
- * @param args args.
- */
- public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
deleted file mode 100644
index e393786e29d9..000000000000
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.wallpapers.gl;
-
-import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
-import static android.opengl.GLES20.glClear;
-import static android.opengl.GLES20.glClearColor;
-import static android.opengl.GLES20.glViewport;
-
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Size;
-
-import com.android.systemui.R;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Consumer;
-
-/**
- * A GL renderer for image wallpaper.
- */
-public class ImageWallpaperRenderer implements GLWallpaperRenderer {
- private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- private final ImageGLProgram mProgram;
- private final ImageGLWallpaper mWallpaper;
- private final Rect mSurfaceSize = new Rect();
- private final WallpaperTexture mTexture;
- private Consumer<Bitmap> mOnBitmapUpdated;
-
- public ImageWallpaperRenderer(Context context) {
- final WallpaperManager wpm = context.getSystemService(WallpaperManager.class);
- if (wpm == null) {
- Log.w(TAG, "WallpaperManager not available");
- }
-
- mTexture = new WallpaperTexture(wpm);
- mProgram = new ImageGLProgram(context);
- mWallpaper = new ImageGLWallpaper(mProgram);
- }
-
- /**
- * @hide
- */
- public void setOnBitmapChanged(Consumer<Bitmap> c) {
- mOnBitmapUpdated = c;
- }
-
- /**
- * @hide
- */
- public void use(Consumer<Bitmap> c) {
- mTexture.use(c);
- }
-
- @Override
- public boolean isWcgContent() {
- return mTexture.isWcgContent();
- }
-
- @Override
- public void onSurfaceCreated() {
- glClearColor(0f, 0f, 0f, 1.0f);
- mProgram.useGLProgram(
- R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
-
- mTexture.use(bitmap -> {
- if (bitmap == null) {
- Log.w(TAG, "reload texture failed!");
- } else if (mOnBitmapUpdated != null) {
- mOnBitmapUpdated.accept(bitmap);
- }
- mWallpaper.setup(bitmap);
- });
- }
-
- @Override
- public void onSurfaceChanged(int width, int height) {
- glViewport(0, 0, width, height);
- }
-
- @Override
- public void onDrawFrame() {
- glClear(GL_COLOR_BUFFER_BIT);
- glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height());
- mWallpaper.useTexture();
- mWallpaper.draw();
- }
-
- @Override
- public Size reportSurfaceSize() {
- mSurfaceSize.set(mTexture.getTextureDimensions());
- return new Size(mSurfaceSize.width(), mSurfaceSize.height());
- }
-
- @Override
- public void finish() {
- }
-
- @Override
- public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
- out.print(prefix); out.print("mSurfaceSize="); out.print(mSurfaceSize);
- out.print(prefix); out.print("mWcgContent="); out.print(isWcgContent());
- mWallpaper.dump(prefix, fd, out, args);
- }
-
- static class WallpaperTexture {
- private final AtomicInteger mRefCount;
- private final Rect mDimensions;
- private final WallpaperManager mWallpaperManager;
- private Bitmap mBitmap;
- private boolean mWcgContent;
- private boolean mTextureUsed;
-
- private WallpaperTexture(WallpaperManager wallpaperManager) {
- mWallpaperManager = wallpaperManager;
- mRefCount = new AtomicInteger();
- mDimensions = new Rect();
- }
-
- public void use(Consumer<Bitmap> consumer) {
- mRefCount.incrementAndGet();
- synchronized (mRefCount) {
- if (mBitmap == null) {
- mBitmap = mWallpaperManager.getBitmapAsUser(UserHandle.USER_CURRENT,
- false /* hardware */);
- mWcgContent = mWallpaperManager.wallpaperSupportsWcg(
- WallpaperManager.FLAG_SYSTEM);
- mWallpaperManager.forgetLoadedWallpaper();
- if (mBitmap != null) {
- mDimensions.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
- mTextureUsed = true;
- } else {
- Log.w(TAG, "Can't get bitmap");
- }
- }
- }
- if (consumer != null) {
- consumer.accept(mBitmap);
- }
- synchronized (mRefCount) {
- final int count = mRefCount.decrementAndGet();
- if (count == 0 && mBitmap != null) {
- if (DEBUG) {
- Log.v(TAG, "WallpaperTexture: release 0x" + getHash()
- + ", refCount=" + count);
- }
- mBitmap.recycle();
- mBitmap = null;
- }
- }
- }
-
- private boolean isWcgContent() {
- return mWcgContent;
- }
-
- private String getHash() {
- return mBitmap != null ? Integer.toHexString(mBitmap.hashCode()) : "null";
- }
-
- private Rect getTextureDimensions() {
- if (!mTextureUsed) {
- mDimensions.set(mWallpaperManager.peekBitmapDimensions());
- }
- return mDimensions;
- }
-
- @Override
- public String toString() {
- return "{" + getHash() + ", " + mRefCount.get() + "}";
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index 4903d31f89f4..8bbaf3dff1e5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -19,7 +19,6 @@ package com.android.keyguard;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -88,7 +87,6 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase {
when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true);
when(mAbsKeyInputView.requireViewById(R.id.bouncer_message_area))
.thenReturn(mKeyguardMessageArea);
- when(mAbsKeyInputView.getResources()).thenReturn(getContext().getResources());
mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector,
@@ -127,22 +125,4 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase {
verifyZeroInteractions(mKeyguardSecurityCallback);
verifyZeroInteractions(mKeyguardMessageAreaController);
}
-
- @Test
- public void onPromptReasonNone_doesNotSetMessage() {
- mKeyguardAbsKeyInputViewController.showPromptReason(0);
- verify(mKeyguardMessageAreaController, never()).setMessage(
- getContext().getResources().getString(R.string.kg_prompt_reason_restart_password),
- false);
- }
-
- @Test
- public void onPromptReason_setsMessage() {
- when(mAbsKeyInputView.getPromptReasonStringRes(1)).thenReturn(
- R.string.kg_prompt_reason_restart_password);
- mKeyguardAbsKeyInputViewController.showPromptReason(1);
- verify(mKeyguardMessageAreaController).setMessage(
- getContext().getResources().getString(R.string.kg_prompt_reason_restart_password),
- false);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 61c7bb500e6a..c8e753844c64 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -29,7 +29,6 @@ import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.graphics.Rect;
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
@@ -47,6 +46,8 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.ClockEvents;
+import com.android.systemui.plugins.ClockFaceController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
@@ -88,7 +89,15 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Mock
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
- private ClockController mClock;
+ private ClockController mClockController;
+ @Mock
+ private ClockFaceController mLargeClockController;
+ @Mock
+ private ClockFaceController mSmallClockController;
+ @Mock
+ private ClockAnimations mClockAnimations;
+ @Mock
+ private ClockEvents mClockEvents;
@Mock
DumpManager mDumpManager;
@Mock
@@ -97,10 +106,12 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Mock
private NotificationIconContainer mNotificationIcons;
@Mock
- private AnimatableClockView mClockView;
+ private AnimatableClockView mSmallClockView;
@Mock
private AnimatableClockView mLargeClockView;
@Mock
+ private FrameLayout mSmallClockFrame;
+ @Mock
private FrameLayout mLargeClockFrame;
@Mock
private SecureSettings mSecureSettings;
@@ -121,9 +132,14 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
mock(RelativeLayout.LayoutParams.class));
when(mView.getContext()).thenReturn(getContext());
when(mView.getResources()).thenReturn(mResources);
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
+ .thenReturn(100);
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin))
+ .thenReturn(-200);
when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
- when(mClockView.getContext()).thenReturn(getContext());
+ when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
+ when(mSmallClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext());
when(mView.isAttachedToWindow()).thenReturn(true);
@@ -144,7 +160,14 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
- when(mClockRegistry.createCurrentClock()).thenReturn(mClock);
+ when(mLargeClockController.getView()).thenReturn(mLargeClockView);
+ when(mSmallClockController.getView()).thenReturn(mSmallClockView);
+ when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
+ when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
+ when(mClockController.getEvents()).thenReturn(mClockEvents);
+ when(mClockController.getAnimations()).thenReturn(mClockAnimations);
+ when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
+ when(mClockEventController.getClock()).thenReturn(mClockController);
mSliceView = new View(getContext());
when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
@@ -203,8 +226,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
listenerArgumentCaptor.getValue().onClockChanged();
- verify(mView, times(2)).setClock(mClock, StatusBarState.SHADE);
- verify(mClockEventController, times(2)).setClock(mClock);
+ verify(mView, times(2)).setClock(mClockController, StatusBarState.SHADE);
+ verify(mClockEventController, times(2)).setClock(mClockController);
}
@Test
@@ -262,17 +285,40 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Test
public void testGetClockAnimationsForwardsToClock() {
- ClockController mockClockController = mock(ClockController.class);
- ClockAnimations mockClockAnimations = mock(ClockAnimations.class);
- when(mClockEventController.getClock()).thenReturn(mockClockController);
- when(mockClockController.getAnimations()).thenReturn(mockClockAnimations);
-
- Rect r1 = new Rect(1, 2, 3, 4);
- Rect r2 = new Rect(5, 6, 7, 8);
- mController.getClockAnimations().onPositionUpdated(r1, r2, 0.2f);
- verify(mockClockAnimations).onPositionUpdated(r1, r2, 0.2f);
+ assertEquals(mClockAnimations, mController.getClockAnimations());
+ }
+
+ @Test
+ public void testGetLargeClockBottom_returnsExpectedValue() {
+ when(mLargeClockFrame.getVisibility()).thenReturn(View.VISIBLE);
+ when(mLargeClockFrame.getHeight()).thenReturn(100);
+ when(mSmallClockFrame.getHeight()).thenReturn(50);
+ when(mLargeClockView.getHeight()).thenReturn(40);
+ when(mSmallClockView.getHeight()).thenReturn(20);
+ mController.init();
+
+ assertEquals(170, mController.getClockBottom(1000));
}
+ @Test
+ public void testGetSmallLargeClockBottom_returnsExpectedValue() {
+ when(mLargeClockFrame.getVisibility()).thenReturn(View.GONE);
+ when(mLargeClockFrame.getHeight()).thenReturn(100);
+ when(mSmallClockFrame.getHeight()).thenReturn(50);
+ when(mLargeClockView.getHeight()).thenReturn(40);
+ when(mSmallClockView.getHeight()).thenReturn(20);
+ mController.init();
+
+ assertEquals(1120, mController.getClockBottom(1000));
+ }
+
+ @Test
+ public void testGetClockBottom_nullClock_returnsZero() {
+ when(mClockEventController.getClock()).thenReturn(null);
+ assertEquals(0, mController.getClockBottom(10));
+ }
+
+
private void verifyAttachment(VerificationMode times) {
verify(mClockRegistry, times).registerClockChangeListener(
any(ClockRegistry.ClockChangeListener.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index d91279399341..d20be56d6c6b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -30,54 +30,64 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class KeyguardPasswordViewControllerTest : SysuiTestCase() {
- @Mock private lateinit var keyguardPasswordView: KeyguardPasswordView
- @Mock private lateinit var passwordEntry: EditText
- @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock lateinit var securityMode: KeyguardSecurityModel.SecurityMode
- @Mock lateinit var lockPatternUtils: LockPatternUtils
- @Mock lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
- @Mock lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
- @Mock lateinit var latencyTracker: LatencyTracker
- @Mock lateinit var inputMethodManager: InputMethodManager
- @Mock lateinit var emergencyButtonController: EmergencyButtonController
- @Mock lateinit var mainExecutor: DelayableExecutor
- @Mock lateinit var falsingCollector: FalsingCollector
- @Mock lateinit var keyguardViewController: KeyguardViewController
- @Mock private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
- @Mock
- private lateinit var mKeyguardMessageAreaController:
- KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+ @Mock
+ private lateinit var keyguardPasswordView: KeyguardPasswordView
+ @Mock
+ private lateinit var passwordEntry: EditText
+ @Mock
+ lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock
+ lateinit var securityMode: KeyguardSecurityModel.SecurityMode
+ @Mock
+ lateinit var lockPatternUtils: LockPatternUtils
+ @Mock
+ lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
+ @Mock
+ lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
+ @Mock
+ lateinit var latencyTracker: LatencyTracker
+ @Mock
+ lateinit var inputMethodManager: InputMethodManager
+ @Mock
+ lateinit var emergencyButtonController: EmergencyButtonController
+ @Mock
+ lateinit var mainExecutor: DelayableExecutor
+ @Mock
+ lateinit var falsingCollector: FalsingCollector
+ @Mock
+ lateinit var keyguardViewController: KeyguardViewController
+ @Mock
+ private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
+ @Mock
+ private lateinit var mKeyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
- private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
+ private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- Mockito.`when`(
- keyguardPasswordView.requireViewById<BouncerKeyguardMessageArea>(
- R.id.bouncer_message_area))
- .thenReturn(mKeyguardMessageArea)
- Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea))
- .thenReturn(mKeyguardMessageAreaController)
- Mockito.`when`(keyguardPasswordView.passwordTextViewId).thenReturn(R.id.passwordEntry)
- Mockito.`when`(keyguardPasswordView.findViewById<EditText>(R.id.passwordEntry))
- .thenReturn(passwordEntry)
- `when`(keyguardPasswordView.resources).thenReturn(context.resources)
- keyguardPasswordViewController =
- KeyguardPasswordViewController(
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ Mockito.`when`(
+ keyguardPasswordView
+ .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area)
+ ).thenReturn(mKeyguardMessageArea)
+ Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea))
+ .thenReturn(mKeyguardMessageAreaController)
+ Mockito.`when`(keyguardPasswordView.passwordTextViewId).thenReturn(R.id.passwordEntry)
+ Mockito.`when`(keyguardPasswordView.findViewById<EditText>(R.id.passwordEntry)
+ ).thenReturn(passwordEntry)
+ keyguardPasswordViewController = KeyguardPasswordViewController(
keyguardPasswordView,
keyguardUpdateMonitor,
securityMode,
@@ -90,48 +100,51 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() {
mainExecutor,
mContext.resources,
falsingCollector,
- keyguardViewController)
- }
+ keyguardViewController
+ )
+ }
- @Test
- fun testFocusWhenBouncerIsShown() {
- Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(true)
- Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
- keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
- keyguardPasswordView.post {
- verify(keyguardPasswordView).requestFocus()
- verify(keyguardPasswordView).showKeyboard()
+ @Test
+ fun testFocusWhenBouncerIsShown() {
+ Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(true)
+ Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
+ keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
+ keyguardPasswordView.post {
+ verify(keyguardPasswordView).requestFocus()
+ verify(keyguardPasswordView).showKeyboard()
+ }
}
- }
- @Test
- fun testDoNotFocusWhenBouncerIsHidden() {
- Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(false)
- Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
- keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
- verify(keyguardPasswordView, never()).requestFocus()
- }
+ @Test
+ fun testDoNotFocusWhenBouncerIsHidden() {
+ Mockito.`when`(keyguardViewController.isBouncerShowing).thenReturn(false)
+ Mockito.`when`(keyguardPasswordView.isShown).thenReturn(true)
+ keyguardPasswordViewController.onResume(KeyguardSecurityView.VIEW_REVEALED)
+ verify(keyguardPasswordView, never()).requestFocus()
+ }
- @Test
- fun testHideKeyboardWhenOnPause() {
- keyguardPasswordViewController.onPause()
- keyguardPasswordView.post {
- verify(keyguardPasswordView).clearFocus()
- verify(keyguardPasswordView).hideKeyboard()
+ @Test
+ fun testHideKeyboardWhenOnPause() {
+ keyguardPasswordViewController.onPause()
+ keyguardPasswordView.post {
+ verify(keyguardPasswordView).clearFocus()
+ verify(keyguardPasswordView).hideKeyboard()
+ }
}
- }
- @Test
- fun startAppearAnimation() {
- keyguardPasswordViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController)
- .setMessage(context.resources.getString(R.string.keyguard_enter_your_password), false)
- }
+ @Test
+ fun startAppearAnimation() {
+ keyguardPasswordViewController.startAppearAnimation()
+ verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_password)
+ }
- @Test
- fun startAppearAnimation_withExistingMessage() {
- `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
- keyguardPasswordViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean())
- }
+ @Test
+ fun startAppearAnimation_withExistingMessage() {
+ `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
+ keyguardPasswordViewController.startAppearAnimation()
+ verify(
+ mKeyguardMessageAreaController,
+ never()
+ ).setMessage(R.string.keyguard_enter_your_password)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 85dbdb8330a3..b3d1c8f909d8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -30,93 +30,97 @@ import com.android.systemui.statusbar.policy.DevicePostureController
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
-import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.never
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class KeyguardPatternViewControllerTest : SysuiTestCase() {
- @Mock private lateinit var mKeyguardPatternView: KeyguardPatternView
+ @Mock
+ private lateinit var mKeyguardPatternView: KeyguardPatternView
- @Mock private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock
+ private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode
+ @Mock
+ private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode
- @Mock private lateinit var mLockPatternUtils: LockPatternUtils
+ @Mock
+ private lateinit var mLockPatternUtils: LockPatternUtils
- @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
+ @Mock
+ private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
- @Mock private lateinit var mLatencyTracker: LatencyTracker
- private var mFalsingCollector: FalsingCollector = FalsingCollectorFake()
+ @Mock
+ private lateinit var mLatencyTracker: LatencyTracker
+ private var mFalsingCollector: FalsingCollector = FalsingCollectorFake()
- @Mock private lateinit var mEmergencyButtonController: EmergencyButtonController
+ @Mock
+ private lateinit var mEmergencyButtonController: EmergencyButtonController
- @Mock
- private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
+ @Mock
+ private lateinit
+ var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
- @Mock private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
+ @Mock
+ private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
- @Mock
- private lateinit var mKeyguardMessageAreaController:
- KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+ @Mock
+ private lateinit var mKeyguardMessageAreaController:
+ KeyguardMessageAreaController<BouncerKeyguardMessageArea>
- @Mock private lateinit var mLockPatternView: LockPatternView
+ @Mock
+ private lateinit var mLockPatternView: LockPatternView
- @Mock private lateinit var mPostureController: DevicePostureController
+ @Mock
+ private lateinit var mPostureController: DevicePostureController
- private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
+ private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
- `when`(
- mKeyguardPatternView.requireViewById<BouncerKeyguardMessageArea>(
- R.id.bouncer_message_area))
- .thenReturn(mKeyguardMessageArea)
- `when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
- .thenReturn(mLockPatternView)
- `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea))
- .thenReturn(mKeyguardMessageAreaController)
- `when`(mKeyguardPatternView.resources).thenReturn(context.resources)
- mKeyguardPatternViewController =
- KeyguardPatternViewController(
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
+ `when`(mKeyguardPatternView
+ .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area))
+ .thenReturn(mKeyguardMessageArea)
+ `when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
+ .thenReturn(mLockPatternView)
+ `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea))
+ .thenReturn(mKeyguardMessageAreaController)
+ mKeyguardPatternViewController = KeyguardPatternViewController(
mKeyguardPatternView,
- mKeyguardUpdateMonitor,
- mSecurityMode,
- mLockPatternUtils,
- mKeyguardSecurityCallback,
- mLatencyTracker,
- mFalsingCollector,
- mEmergencyButtonController,
- mKeyguardMessageAreaControllerFactory,
- mPostureController)
- }
-
- @Test
- fun onPause_resetsText() {
- mKeyguardPatternViewController.init()
- mKeyguardPatternViewController.onPause()
- verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern)
- }
-
- @Test
- fun startAppearAnimation() {
- mKeyguardPatternViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController)
- .setMessage(context.resources.getString(R.string.keyguard_enter_your_pattern), false)
- }
-
- @Test
- fun startAppearAnimation_withExistingMessage() {
- `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
- mKeyguardPatternViewController.startAppearAnimation()
- verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean())
- }
+ mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
+ mLatencyTracker, mFalsingCollector, mEmergencyButtonController,
+ mKeyguardMessageAreaControllerFactory, mPostureController
+ )
+ }
+
+ @Test
+ fun onPause_resetsText() {
+ mKeyguardPatternViewController.init()
+ mKeyguardPatternViewController.onPause()
+ verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern)
+ }
+
+
+ @Test
+ fun startAppearAnimation() {
+ mKeyguardPatternViewController.startAppearAnimation()
+ verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern)
+ }
+
+ @Test
+ fun startAppearAnimation_withExistingMessage() {
+ `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.")
+ mKeyguardPatternViewController.startAppearAnimation()
+ verify(
+ mKeyguardMessageAreaController,
+ never()
+ ).setMessage(R.string.keyguard_enter_your_password)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index cdb7bbb9f823..8bcfe6f2b6f5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -31,13 +31,10 @@ import com.android.systemui.statusbar.policy.DevicePostureController
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.any
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -82,7 +79,6 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
keyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea::class.java))
)
.thenReturn(keyguardMessageAreaController)
- `when`(keyguardPinView.resources).thenReturn(context.resources)
pinViewController =
KeyguardPinViewController(
keyguardPinView,
@@ -102,14 +98,14 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
@Test
fun startAppearAnimation() {
pinViewController.startAppearAnimation()
- verify(keyguardMessageAreaController)
- .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
+ verify(keyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pin)
}
@Test
fun startAppearAnimation_withExistingMessage() {
Mockito.`when`(keyguardMessageAreaController.message).thenReturn("Unlock to continue.")
pinViewController.startAppearAnimation()
- verify(keyguardMessageAreaController, Mockito.never()).setMessage(anyString(), anyBoolean())
+ verify(keyguardMessageAreaController, Mockito.never())
+ .setMessage(R.string.keyguard_enter_your_password)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index b2c52668e057..0cdd6e2ce85e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -20,8 +20,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import android.graphics.PointF;
import android.testing.AndroidTestingRunner;
@@ -30,6 +32,10 @@ import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.WindowManager;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.FlingAnimation;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
import androidx.test.filters.SmallTest;
import com.android.systemui.Prefs;
@@ -39,6 +45,9 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Optional;
/** Tests for {@link MenuAnimationController}. */
@RunWith(AndroidTestingRunner.class)
@@ -47,9 +56,10 @@ import org.junit.runner.RunWith;
public class MenuAnimationControllerTest extends SysuiTestCase {
private boolean mLastIsMoveToTucked;
+ private ArgumentCaptor<DynamicAnimation.OnAnimationEndListener> mEndListenerCaptor;
private ViewPropertyAnimator mViewPropertyAnimator;
private MenuView mMenuView;
- private MenuAnimationController mMenuAnimationController;
+ private TestMenuAnimationController mMenuAnimationController;
@Before
public void setUp() throws Exception {
@@ -62,15 +72,17 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
mViewPropertyAnimator = spy(mMenuView.animate());
doReturn(mViewPropertyAnimator).when(mMenuView).animate();
- mMenuAnimationController = new MenuAnimationController(mMenuView);
+ mMenuAnimationController = new TestMenuAnimationController(mMenuView);
mLastIsMoveToTucked = Prefs.getBoolean(mContext,
Prefs.Key.HAS_ACCESSIBILITY_FLOATING_MENU_TUCKED, /* defaultValue= */ false);
+ mEndListenerCaptor = ArgumentCaptor.forClass(DynamicAnimation.OnAnimationEndListener.class);
}
@After
public void tearDown() throws Exception {
Prefs.putBoolean(mContext, Prefs.Key.HAS_ACCESSIBILITY_FLOATING_MENU_TUCKED,
mLastIsMoveToTucked);
+ mEndListenerCaptor.getAllValues().clear();
}
@Test
@@ -122,4 +134,115 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
assertThat(isMoveToTucked).isFalse();
}
+
+ @Test
+ public void startTuckedAnimationPreview_hasAnimation() {
+ mMenuView.clearAnimation();
+
+ mMenuAnimationController.startTuckedAnimationPreview();
+
+ assertThat(mMenuView.getAnimation()).isNotNull();
+ }
+
+ @Test
+ public void startSpringAnimationsAndEndOneAnimation_notTriggerEndAction() {
+ final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
+ mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
+
+ setupAndRunSpringAnimations();
+ final Optional<DynamicAnimation> anyAnimation =
+ mMenuAnimationController.mPositionAnimations.values().stream().findAny();
+ anyAnimation.ifPresent(this::skipAnimationToEnd);
+
+ verifyZeroInteractions(onSpringAnimationsEndCallback);
+ }
+
+ @Test
+ public void startAndEndSpringAnimations_triggerEndAction() {
+ final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
+ mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
+
+ setupAndRunSpringAnimations();
+ mMenuAnimationController.mPositionAnimations.values().forEach(this::skipAnimationToEnd);
+
+ verify(onSpringAnimationsEndCallback).run();
+ }
+
+ @Test
+ public void flingThenSpringAnimationsAreEnded_triggerEndAction() {
+ final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
+ mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
+
+ mMenuAnimationController.flingMenuThenSpringToEdge(/* x= */ 0, /* velocityX= */
+ 100, /* velocityY= */ 100);
+ mMenuAnimationController.mPositionAnimations.values()
+ .forEach(animation -> verify((FlingAnimation) animation).addEndListener(
+ mEndListenerCaptor.capture()));
+ mEndListenerCaptor.getAllValues()
+ .forEach(listener -> listener.onAnimationEnd(mock(DynamicAnimation.class),
+ /* canceled */ false, /* endValue */ 0, /* endVelocity */ 0));
+ mMenuAnimationController.mPositionAnimations.values().forEach(this::skipAnimationToEnd);
+
+ verify(onSpringAnimationsEndCallback).run();
+ }
+
+ @Test
+ public void existFlingIsRunningAndTheOtherAreEnd_notTriggerEndAction() {
+ final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
+ mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
+
+ mMenuAnimationController.flingMenuThenSpringToEdge(/* x= */ 0, /* velocityX= */
+ 200, /* velocityY= */ 200);
+ mMenuAnimationController.mPositionAnimations.values()
+ .forEach(animation -> verify((FlingAnimation) animation).addEndListener(
+ mEndListenerCaptor.capture()));
+ final Optional<DynamicAnimation.OnAnimationEndListener> anyAnimation =
+ mEndListenerCaptor.getAllValues().stream().findAny();
+ anyAnimation.ifPresent(
+ listener -> listener.onAnimationEnd(mock(DynamicAnimation.class), /* canceled */
+ false, /* endValue */ 0, /* endVelocity */ 0));
+ mMenuAnimationController.mPositionAnimations.values()
+ .stream()
+ .filter(animation -> animation instanceof SpringAnimation)
+ .forEach(this::skipAnimationToEnd);
+
+ verifyZeroInteractions(onSpringAnimationsEndCallback);
+ }
+
+ private void setupAndRunSpringAnimations() {
+ final float stiffness = 700f;
+ final float dampingRatio = 0.85f;
+ final float velocity = 100f;
+ final float finalPosition = 300f;
+
+ mMenuAnimationController.springMenuWith(DynamicAnimation.TRANSLATION_X, new SpringForce()
+ .setStiffness(stiffness)
+ .setDampingRatio(dampingRatio), velocity, finalPosition);
+ mMenuAnimationController.springMenuWith(DynamicAnimation.TRANSLATION_Y, new SpringForce()
+ .setStiffness(stiffness)
+ .setDampingRatio(dampingRatio), velocity, finalPosition);
+ }
+
+ private void skipAnimationToEnd(DynamicAnimation animation) {
+ final SpringAnimation springAnimation = ((SpringAnimation) animation);
+ // The doAnimationFrame function is used for skipping animation to the end.
+ springAnimation.doAnimationFrame(100);
+ springAnimation.skipToEnd();
+ springAnimation.doAnimationFrame(200);
+ }
+
+ /**
+ * Wrapper class for testing.
+ */
+ private static class TestMenuAnimationController extends MenuAnimationController {
+ TestMenuAnimationController(MenuView menuView) {
+ super(menuView);
+ }
+
+ @Override
+ FlingAnimation createFlingAnimation(MenuView menuView,
+ MenuPositionProperty menuPositionProperty) {
+ return spy(super.createFlingAnimation(menuView, menuPositionProperty));
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
new file mode 100644
index 000000000000..42b610a18bc0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for {@link MenuEduTooltipView}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class MenuEduTooltipViewTest extends SysuiTestCase {
+ private MenuViewAppearance mMenuViewAppearance;
+ private MenuEduTooltipView mMenuEduTooltipView;
+
+ @Before
+ public void setUp() throws Exception {
+ final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ mMenuViewAppearance = new MenuViewAppearance(mContext, windowManager);
+ mMenuEduTooltipView = new MenuEduTooltipView(mContext, mMenuViewAppearance);
+ }
+
+ @Test
+ public void show_matchMessageText() {
+ final CharSequence text = "Message";
+
+ mMenuEduTooltipView.show(text);
+
+ final TextView messageView = mMenuEduTooltipView.findViewById(R.id.text);
+ assertThat(messageView.getText().toString().contentEquals(text)).isTrue();
+ }
+
+ @Test
+ public void show_menuOnLeft_onRightOfAnchor() {
+ mMenuViewAppearance.setPercentagePosition(
+ new Position(/* percentageX= */ 0.0f, /* percentageY= */ 0.0f));
+ final CharSequence text = "Message";
+
+ mMenuEduTooltipView.show(text);
+ final int tooltipViewX = (int) (mMenuViewAppearance.getMenuPosition().x
+ + mMenuViewAppearance.getMenuWidth());
+
+ assertThat(mMenuEduTooltipView.getX()).isEqualTo(tooltipViewX);
+ }
+
+ @Test
+ public void show_menuCloseToLeftOfCenter_onLeftOfAnchor() {
+ mMenuViewAppearance.setPercentagePosition(
+ new Position(/* percentageX= */ 0.4f, /* percentageY= */ 0.0f));
+ final CharSequence text = "Message";
+
+ mMenuEduTooltipView.show(text);
+ final int tooltipViewX = (int) (mMenuViewAppearance.getMenuPosition().x
+ + mMenuViewAppearance.getMenuWidth());
+
+ assertThat(mMenuEduTooltipView.getX()).isEqualTo(tooltipViewX);
+ }
+
+ @Test
+ public void show_menuOnRight_onLeftOfAnchor() {
+ mMenuViewAppearance.setPercentagePosition(
+ new Position(/* percentageX= */ 1.0f, /* percentageY= */ 0.0f));
+ final Resources res = getContext().getResources();
+ final int arrowWidth =
+ res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_width);
+ final int arrowMargin =
+ res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_margin);
+ final CharSequence text = "Message";
+
+ mMenuEduTooltipView.show(text);
+ final TextView messageView = mMenuEduTooltipView.findViewById(R.id.text);
+ final int layoutWidth = messageView.getMeasuredWidth() + arrowWidth + arrowMargin;
+
+ assertThat(mMenuEduTooltipView.getX()).isEqualTo(
+ mMenuViewAppearance.getMenuPosition().x - layoutWidth);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index 4acb394bee95..d29ebb86686f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -181,6 +181,20 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase {
verify(mMenuAnimationController).moveToEdgeAndHide();
}
+ @Test
+ public void receiveActionDownMotionEvent_verifyOnActionDownEnd() {
+ final Runnable onActionDownEnd = mock(Runnable.class);
+ mTouchHandler.setOnActionDownEndListener(onActionDownEnd);
+
+ final MotionEvent stubDownEvent =
+ mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, /* eventTime= */ 1,
+ MotionEvent.ACTION_DOWN, mStubMenuView.getTranslationX(),
+ mStubMenuView.getTranslationY());
+ mTouchHandler.onInterceptTouchEvent(mStubListView, stubDownEvent);
+
+ verify(onActionDownEnd).run();
+ }
+
@After
public void tearDown() {
mMotionEventHelper.recycleEvents();
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 a94f3427eebe..b061eb395119 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
@@ -23,6 +24,8 @@ import static android.view.MotionEvent.ACTION_UP;
import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -124,7 +127,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Unit under test
private UdfpsController mUdfpsController;
// Dependencies
- private FakeExecutor mBiometricsExecutor;
+ private FakeExecutor mBiometricExecutor;
@Mock
private LayoutInflater mLayoutInflater;
@Mock
@@ -212,6 +215,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
private ArgumentCaptor<Runnable> mOnDisplayConfiguredCaptor;
@Captor
private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
+ @Captor
+ private ArgumentCaptor<UdfpsController.UdfpsOverlayController> mUdfpsOverlayControllerCaptor;
private ScreenLifecycle.Observer mScreenObserver;
private FingerprintSensorPropertiesInternal mOpticalProps;
private FingerprintSensorPropertiesInternal mUltrasonicProps;
@@ -258,7 +263,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFgExecutor = new FakeExecutor(new FakeSystemClock());
// Create a fake background executor.
- mBiometricsExecutor = new FakeExecutor(new FakeSystemClock());
+ mBiometricExecutor = new FakeExecutor(new FakeSystemClock());
initUdfpsController(true /* hasAlternateTouchProvider */);
}
@@ -286,7 +291,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mVibrator, mUdfpsHapticsSimulator, mUdfpsShell, mKeyguardStateController,
mDisplayManager, mHandler, mConfigurationController, mSystemClock,
mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker,
- mActivityLaunchAnimator, alternateTouchProvider, mBiometricsExecutor,
+ mActivityLaunchAnimator, alternateTouchProvider, mBiometricExecutor,
mPrimaryBouncerInteractor, mSinglePointerTouchProcessor);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
@@ -322,7 +327,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
downEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
@@ -360,7 +365,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFgExecutor.runAllReady();
}
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
moveEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
@@ -384,12 +389,12 @@ public class UdfpsControllerTest extends SysuiTestCase {
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
downEvent.recycle();
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
moveEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
@@ -578,11 +583,11 @@ public class UdfpsControllerTest extends SysuiTestCase {
MotionEvent event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor,
touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
if (testParams.hasAlternateTouchProvider) {
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
@@ -601,11 +606,11 @@ public class UdfpsControllerTest extends SysuiTestCase {
scaleFactor, Surface.ROTATION_90));
event = obtainMotionEvent(ACTION_DOWN, displayHeight, 0, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, displayHeight, 0, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
if (testParams.hasAlternateTouchProvider) {
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
@@ -624,11 +629,11 @@ public class UdfpsControllerTest extends SysuiTestCase {
scaleFactor, Surface.ROTATION_270));
event = obtainMotionEvent(ACTION_DOWN, 0, displayWidth, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, 0, displayWidth, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
if (testParams.hasAlternateTouchProvider) {
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
@@ -648,11 +653,11 @@ public class UdfpsControllerTest extends SysuiTestCase {
// ROTATION_180 is not supported. It should be treated like ROTATION_0.
event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
event.recycle();
if (testParams.hasAlternateTouchProvider) {
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
@@ -687,12 +692,12 @@ public class UdfpsControllerTest extends SysuiTestCase {
// WHEN ACTION_DOWN is received
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
downEvent.recycle();
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
moveEvent.recycle();
mFgExecutor.runAllReady();
@@ -725,7 +730,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
// AND onDisplayConfigured notifies FingerprintManager about onUiReady
mOnDisplayConfiguredCaptor.getValue().run();
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
if (testParams.hasAlternateTouchProvider) {
InOrder inOrder = inOrder(mAlternateTouchProvider, mLatencyTracker);
inOrder.verify(mAlternateTouchProvider).onUiReady();
@@ -748,13 +753,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
}
+
+
@Test
public void aodInterrupt() {
runWithAllParams(this::aodInterruptParameterized);
}
private void aodInterruptParameterized(TestParams testParams) throws RemoteException {
- mUdfpsController.cancelAodInterrupt();
+ mUdfpsController.cancelAodSendFingerUpAction();
reset(mUdfpsView, mAlternateTouchProvider, mFingerprintManager, mKeyguardUpdateMonitor);
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
@@ -774,7 +781,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
} else {
verify(mUdfpsView, never()).configureDisplay(mOnDisplayConfiguredCaptor.capture());
}
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
if (testParams.hasAlternateTouchProvider) {
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0),
@@ -792,7 +799,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
- public void cancelAodInterrupt() {
+ public void tryAodSendFingerUp_displayConfigurationChanges() {
runWithAllParams(this::cancelAodInterruptParameterized);
}
@@ -808,24 +815,25 @@ public class UdfpsControllerTest extends SysuiTestCase {
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
// WHEN it is cancelled
- mUdfpsController.cancelAodInterrupt();
+ mUdfpsController.tryAodSendFingerUp();
// THEN the display is unconfigured
verify(mUdfpsView).unconfigureDisplay();
} else {
when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
// WHEN it is cancelled
- mUdfpsController.cancelAodInterrupt();
+ mUdfpsController.tryAodSendFingerUp();
// THEN the display configuration is unchanged.
verify(mUdfpsView, never()).unconfigureDisplay();
}
}
@Test
- public void aodInterruptTimeout() {
- runWithAllParams(this::aodInterruptTimeoutParameterized);
+ public void onFingerUp_displayConfigurationChange() {
+ runWithAllParams(this::onFingerUp_displayConfigurationParameterized);
}
- private void aodInterruptTimeoutParameterized(TestParams testParams) throws RemoteException {
+ private void onFingerUp_displayConfigurationParameterized(TestParams testParams)
+ throws RemoteException {
reset(mUdfpsView);
// GIVEN AOD interrupt
@@ -834,99 +842,105 @@ public class UdfpsControllerTest extends SysuiTestCase {
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
- mFgExecutor.runAllReady();
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
- } else {
- when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
- }
- // WHEN it times out
- mFgExecutor.advanceClockToNext();
- mFgExecutor.runAllReady();
- if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
- // THEN the display is unconfigured.
+
+ // WHEN up-action received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
+ mBiometricExecutor.runAllReady();
+ upEvent.recycle();
+ mFgExecutor.runAllReady();
+
+ // THEN the display is unconfigured
verify(mUdfpsView).unconfigureDisplay();
} else {
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+
+ // WHEN up-action received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
+ mBiometricExecutor.runAllReady();
+ upEvent.recycle();
+ mFgExecutor.runAllReady();
+
// THEN the display configuration is unchanged.
verify(mUdfpsView, never()).unconfigureDisplay();
}
}
@Test
- public void aodInterruptCancelTimeoutActionOnFingerUp() {
- runWithAllParams(this::aodInterruptCancelTimeoutActionOnFingerUpParameterized);
+ public void onAcquiredGood_displayConfigurationChange() {
+ runWithAllParams(this::onAcquiredGood_displayConfigurationParameterized);
}
- private void aodInterruptCancelTimeoutActionOnFingerUpParameterized(TestParams testParams)
+ private void onAcquiredGood_displayConfigurationParameterized(TestParams testParams)
throws RemoteException {
reset(mUdfpsView);
- when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
- // GIVEN AOD interrupt
+ // GIVEN overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
- mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
- mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
- mFgExecutor.runAllReady();
-
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
- // Configure UdfpsView to accept the ACTION_UP event
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
+ // WHEN ACQUIRED_GOOD received
+ mOverlayController.onAcquired(testParams.sensorProps.sensorId,
+ BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD);
+ mFgExecutor.runAllReady();
+ // THEN the display is unconfigured
+ verify(mUdfpsView).unconfigureDisplay();
} else {
when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+ // WHEN ACQUIRED_GOOD received
+ mOverlayController.onAcquired(testParams.sensorProps.sensorId,
+ BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD);
+ mFgExecutor.runAllReady();
+ // THEN the display configuration is unchanged.
+ verify(mUdfpsView, never()).unconfigureDisplay();
}
+ }
- // WHEN ACTION_UP is received
- verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
- MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
- mBiometricsExecutor.runAllReady();
- upEvent.recycle();
-
- // Configure UdfpsView to accept the ACTION_DOWN event
- when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+ @Test
+ public void aodInterruptTimeout() {
+ runWithAllParams(this::aodInterruptTimeoutParameterized);
+ }
- // WHEN ACTION_DOWN is received
- MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
- downEvent.recycle();
+ private void aodInterruptTimeoutParameterized(TestParams testParams) throws RemoteException {
+ reset(mUdfpsView);
- // WHEN ACTION_MOVE is received
- MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
- mBiometricsExecutor.runAllReady();
- moveEvent.recycle();
+ // GIVEN AOD interrupt
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mScreenObserver.onScreenTurnedOn();
+ mFgExecutor.runAllReady();
+ mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
mFgExecutor.runAllReady();
-
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
- // Configure UdfpsView to accept the finger up event
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
} else {
when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
}
-
// WHEN it times out
mFgExecutor.advanceClockToNext();
mFgExecutor.runAllReady();
-
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
- // THEN the display should be unconfigured once. If the timeout action is not
- // cancelled, the display would be unconfigured twice which would cause two
- // FP attempts.
- verify(mUdfpsView, times(1)).unconfigureDisplay();
+ // THEN the display is unconfigured.
+ verify(mUdfpsView).unconfigureDisplay();
} else {
+ // THEN the display configuration is unchanged.
verify(mUdfpsView, never()).unconfigureDisplay();
}
}
@Test
- public void aodInterruptCancelTimeoutActionOnAcquired() {
- runWithAllParams(this::aodInterruptCancelTimeoutActionOnAcquiredParameterized);
+ public void aodInterruptCancelTimeoutActionOnFingerUp() {
+ runWithAllParams(this::aodInterruptCancelTimeoutActionOnFingerUpParameterized);
}
- private void aodInterruptCancelTimeoutActionOnAcquiredParameterized(TestParams testParams)
+ private void aodInterruptCancelTimeoutActionOnFingerUpParameterized(TestParams testParams)
throws RemoteException {
reset(mUdfpsView);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
@@ -940,30 +954,32 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFgExecutor.runAllReady();
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
- // Configure UdfpsView to accept the acquired event
+ // Configure UdfpsView to accept the ACTION_UP event
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
} else {
when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
}
- // WHEN acquired is received
- mOverlayController.onAcquired(testParams.sensorProps.sensorId,
- BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD);
+ // WHEN ACTION_UP is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
+ mBiometricExecutor.runAllReady();
+ upEvent.recycle();
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
// WHEN ACTION_DOWN is received
- verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
downEvent.recycle();
// WHEN ACTION_MOVE is received
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
moveEvent.recycle();
mFgExecutor.runAllReady();
@@ -1083,11 +1099,11 @@ public class UdfpsControllerTest extends SysuiTestCase {
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
downEvent.recycle();
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
moveEvent.recycle();
// THEN NO haptic played
@@ -1123,19 +1139,19 @@ public class UdfpsControllerTest extends SysuiTestCase {
// WHEN ACTION_DOWN is received
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
downEvent.recycle();
// AND ACTION_MOVE is received
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
moveEvent.recycle();
// AND ACTION_UP is received
MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
upEvent.recycle();
// THEN the old FingerprintManager path is invoked.
@@ -1177,7 +1193,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
processorResultDown);
MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
downEvent.recycle();
// AND ACTION_UP is received
@@ -1185,7 +1201,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
processorResultUp);
MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
- mBiometricsExecutor.runAllReady();
+ mBiometricExecutor.runAllReady();
upEvent.recycle();
// THEN the new FingerprintManager path is invoked.
@@ -1194,4 +1210,31 @@ public class UdfpsControllerTest extends SysuiTestCase {
verify(mFingerprintManager).onPointerUp(anyLong(), anyInt(), anyInt(), anyFloat(),
anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
}
+
+ @Test
+ public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
+ // GIVEN UDFPS overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // GIVEN there's been an AoD interrupt
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+ mScreenObserver.onScreenTurnedOn();
+ mUdfpsController.onAodInterrupt(0, 0, 0, 0);
+
+ // THEN finger is considered down
+ assertTrue(mUdfpsController.isFingerDown());
+
+ // WHEN udfps receives an ACQUIRED_GOOD after the display is configured
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
+ verify(mFingerprintManager).setUdfpsOverlayController(
+ mUdfpsOverlayControllerCaptor.capture());
+ mUdfpsOverlayControllerCaptor.getValue().onAcquired(0, FINGERPRINT_ACQUIRED_GOOD);
+ mFgExecutor.runAllReady();
+
+ // THEN is fingerDown should be FALSE
+ assertFalse(mUdfpsController.isFingerDown());
+
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 517e27a3ce2f..2d412dcaa909 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -27,16 +27,19 @@ import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.KeyguardBouncer
import com.android.systemui.statusbar.phone.KeyguardBypassController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.yield
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
@@ -45,6 +48,7 @@ import org.mockito.MockitoAnnotations
@TestableLooper.RunWithLooper
class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() {
lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
+ @Mock private lateinit var bouncerLogger: TableLogBuffer
@Before
override fun setUp() {
@@ -53,7 +57,8 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle
keyguardBouncerRepository =
KeyguardBouncerRepository(
mock(com.android.keyguard.ViewMediatorCallback::class.java),
- mKeyguardUpdateMonitor
+ TestCoroutineScope(),
+ bouncerLogger,
)
super.setUp()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index c677f19f93e5..35cd3d261562 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -36,6 +36,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags.APP_PANELS_ALL_APPS_ALLOWED
import com.android.systemui.flags.Flags.USE_APP_PANELS
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
@@ -119,6 +120,8 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
// Return true by default, we'll test the false path
`when`(featureFlags.isEnabled(USE_APP_PANELS)).thenReturn(true)
+ // Return false by default, we'll test the true path
+ `when`(featureFlags.isEnabled(APP_PANELS_ALL_APPS_ALLOWED)).thenReturn(false)
val wrapper = object : ContextWrapper(mContext) {
override fun createContextAsUser(user: UserHandle, flags: Int): Context {
@@ -518,6 +521,37 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
}
@Test
+ fun testPackageNotPreferred_allowAllApps_correctPanel() {
+ `when`(featureFlags.isEnabled(APP_PANELS_ALL_APPS_ALLOWED)).thenReturn(true)
+
+ mContext.orCreateTestableResources
+ .addOverride(R.array.config_controlsPreferredPackages, arrayOf<String>())
+
+ val serviceInfo = ServiceInfo(
+ componentName,
+ activityName
+ )
+
+ `when`(packageManager.getComponentEnabledSetting(eq(activityName)))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
+
+ setUpQueryResult(listOf(
+ ActivityInfo(
+ activityName,
+ exported = true,
+ permission = Manifest.permission.BIND_CONTROLS
+ )
+ ))
+
+ val list = listOf(serviceInfo)
+ serviceListingCallbackCaptor.value.onServicesReloaded(list)
+
+ executor.runAllReady()
+
+ assertEquals(activityName, controller.getCurrentServices()[0].panelActivity)
+ }
+
+ @Test
fun testListingsNotModifiedByCallback() {
// This test checks that if the list passed to the callback is modified, it has no effect
// in the resulting services
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 82432ce31fa2..b66a454638ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -357,6 +357,44 @@ public class DozeTriggersTest extends SysuiTestCase {
verify(mDozeLog).tracePulseDropped(anyString(), eq(null));
}
+ @Test
+ public void udfpsLongPress_triggeredWhenAodPaused() {
+ // GIVEN device is DOZE_AOD_PAUSED
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD_PAUSED);
+
+ // WHEN udfps long-press is triggered
+ mTriggers.onSensor(DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, 100, 100,
+ new float[]{0, 1, 2, 3, 4});
+
+ // THEN the pulse is NOT dropped
+ verify(mDozeLog, never()).tracePulseDropped(anyString(), any());
+
+ // WHEN the screen state is ON
+ mTriggers.onScreenState(Display.STATE_ON);
+
+ // THEN aod interrupt is sent
+ verify(mAuthController).onAodInterrupt(anyInt(), anyInt(), anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void udfpsLongPress_triggeredWhenAodPausing() {
+ // GIVEN device is DOZE_AOD_PAUSED
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD_PAUSING);
+
+ // WHEN udfps long-press is triggered
+ mTriggers.onSensor(DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, 100, 100,
+ new float[]{0, 1, 2, 3, 4});
+
+ // THEN the pulse is NOT dropped
+ verify(mDozeLog, never()).tracePulseDropped(anyString(), any());
+
+ // WHEN the screen state is ON
+ mTriggers.onScreenState(Display.STATE_ON);
+
+ // THEN aod interrupt is sent
+ verify(mAuthController).onAodInterrupt(anyInt(), anyInt(), anyFloat(), anyFloat());
+ }
+
private void waitForSensorManager() {
mExecutor.runAllReady();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index ffb8342a56a5..67cf2fcfd1a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.dreams;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -38,13 +39,13 @@ import android.view.WindowManager;
import android.view.WindowManagerImpl;
import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.complication.dagger.ComplicationComponent;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -70,7 +71,7 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@Mock
- LifecycleOwner mLifecycleOwner;
+ DreamOverlayLifecycleOwner mLifecycleOwner;
@Mock
LifecycleRegistry mLifecycleRegistry;
@@ -87,6 +88,12 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
WindowManagerImpl mWindowManager;
@Mock
+ ComplicationComponent.Factory mComplicationComponentFactory;
+
+ @Mock
+ ComplicationComponent mComplicationComponent;
+
+ @Mock
DreamOverlayComponent.Factory mDreamOverlayComponentFactory;
@Mock
@@ -124,19 +131,26 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
when(mDreamOverlayComponent.getDreamOverlayContainerViewController())
.thenReturn(mDreamOverlayContainerViewController);
- when(mDreamOverlayComponent.getLifecycleOwner())
- .thenReturn(mLifecycleOwner);
- when(mDreamOverlayComponent.getLifecycleRegistry())
+ when(mLifecycleOwner.getRegistry())
.thenReturn(mLifecycleRegistry);
when(mDreamOverlayComponent.getDreamOverlayTouchMonitor())
.thenReturn(mDreamOverlayTouchMonitor);
+ when(mComplicationComponentFactory
+ .create())
+ .thenReturn(mComplicationComponent);
+ // TODO(b/261781069): A touch handler should be passed in from the complication component
+ // when the complication component is introduced.
when(mDreamOverlayComponentFactory
- .create(any(), any()))
+ .create(any(), any(), any(), isNull()))
.thenReturn(mDreamOverlayComponent);
when(mDreamOverlayContainerViewController.getContainerView())
.thenReturn(mDreamOverlayContainerView);
- mService = new DreamOverlayService(mContext, mMainExecutor, mWindowManager,
+ mService = new DreamOverlayService(mContext,
+ mMainExecutor,
+ mLifecycleOwner,
+ mWindowManager,
+ mComplicationComponentFactory,
mDreamOverlayComponentFactory,
mStateController,
mKeyguardUpdateMonitor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index c21c7a2aacbe..ee989d1ddab6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -63,7 +63,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testStateChange_overlayActive() {
final DreamOverlayStateController stateController = new DreamOverlayStateController(
- mExecutor);
+ mExecutor, true);
stateController.addCallback(mCallback);
stateController.setOverlayActive(true);
mExecutor.runAllReady();
@@ -85,7 +85,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testCallback() {
final DreamOverlayStateController stateController = new DreamOverlayStateController(
- mExecutor);
+ mExecutor, true);
stateController.addCallback(mCallback);
// Add complication and verify callback is notified.
@@ -111,7 +111,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyOnCallbackAdd() {
final DreamOverlayStateController stateController =
- new DreamOverlayStateController(mExecutor);
+ new DreamOverlayStateController(mExecutor, true);
stateController.addComplication(mComplication);
mExecutor.runAllReady();
@@ -123,9 +123,24 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
}
@Test
+ public void testNotifyOnCallbackAddOverlayDisabled() {
+ final DreamOverlayStateController stateController =
+ new DreamOverlayStateController(mExecutor, false);
+
+ stateController.addComplication(mComplication);
+ mExecutor.runAllReady();
+
+ // Verify callback occurs on add when an overlay is already present.
+ stateController.addCallback(mCallback);
+ mExecutor.runAllReady();
+ verify(mCallback, never()).onComplicationsChanged();
+ }
+
+
+ @Test
public void testComplicationFilteringWhenShouldShowComplications() {
final DreamOverlayStateController stateController =
- new DreamOverlayStateController(mExecutor);
+ new DreamOverlayStateController(mExecutor, true);
stateController.setShouldShowComplications(true);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -165,7 +180,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testComplicationFilteringWhenShouldHideComplications() {
final DreamOverlayStateController stateController =
- new DreamOverlayStateController(mExecutor);
+ new DreamOverlayStateController(mExecutor, true);
stateController.setShouldShowComplications(true);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -212,7 +227,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
public void testComplicationWithNoTypeNotFiltered() {
final Complication complication = Mockito.mock(Complication.class);
final DreamOverlayStateController stateController =
- new DreamOverlayStateController(mExecutor);
+ new DreamOverlayStateController(mExecutor, true);
stateController.addComplication(complication);
mExecutor.runAllReady();
assertThat(stateController.getComplications(true).contains(complication))
@@ -222,7 +237,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyLowLightChanged() {
final DreamOverlayStateController stateController =
- new DreamOverlayStateController(mExecutor);
+ new DreamOverlayStateController(mExecutor, true);
stateController.addCallback(mCallback);
mExecutor.runAllReady();
@@ -238,7 +253,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test
public void testNotifyEntryAnimationsFinishedChanged() {
final DreamOverlayStateController stateController =
- new DreamOverlayStateController(mExecutor);
+ new DreamOverlayStateController(mExecutor, true);
stateController.addCallback(mCallback);
mExecutor.runAllReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
index b477592f8fbc..dcd8736711f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.dreams.complication;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -139,6 +141,21 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
}
@Test
+ public void testMalformedComplicationAddition() {
+ final Observer<Collection<ComplicationViewModel>> observer =
+ captureComplicationViewModelsObserver();
+
+ // Add a complication and ensure it is added to the view.
+ final HashSet<ComplicationViewModel> complications = new HashSet<>(
+ Collections.singletonList(mComplicationViewModel));
+ when(mViewHolder.getView()).thenReturn(null);
+ observer.onChanged(complications);
+
+ verify(mLayoutEngine, never()).addComplication(any(), any(), any(), anyInt());
+
+ }
+
+ @Test
public void testNewComplicationsBeforeEntryAnimationsFinishSetToInvisible() {
final Observer<Collection<ComplicationViewModel>> observer =
captureComplicationViewModelsObserver();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandlerTest.java
index 4e3aca710884..d68f03246bf6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandlerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.dreams.touch;
+package com.android.systemui.dreams.dreamcomplication;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -33,6 +33,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.dreams.touch.DreamTouchHandler;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.touch.TouchInsetManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index d52616bfefcc..c8a352dd7cd2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -16,11 +16,12 @@
package com.android.systemui.globalactions;
+import static android.content.pm.UserInfo.FLAG_ADMIN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@@ -32,11 +33,13 @@ import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.media.AudioManager;
import android.os.Handler;
import android.os.UserManager;
+import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -552,10 +555,32 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
@Test
public void testBugreportAction_whenDebugMode_shouldOfferBugreportButtonBeforeProvisioning() {
- doReturn(1).when(mGlobalSettings).getInt(anyString(), anyInt());
+ UserInfo currentUser = mockCurrentUser(FLAG_ADMIN);
+
+ when(mGlobalActionsDialogLite.getCurrentUser()).thenReturn(currentUser);
+ doReturn(1).when(mGlobalSettings)
+ .getIntForUser(Settings.Global.BUGREPORT_IN_POWER_MENU, 0, currentUser.id);
GlobalActionsDialogLite.BugReportAction bugReportAction =
mGlobalActionsDialogLite.makeBugReportActionForTesting();
assertThat(bugReportAction.showBeforeProvisioning()).isTrue();
}
+
+ @Test
+ public void testBugreportAction_whenUserIsNotAdmin_noBugReportActionBeforeProvisioning() {
+ UserInfo currentUser = mockCurrentUser(0);
+
+ when(mGlobalActionsDialogLite.getCurrentUser()).thenReturn(currentUser);
+ doReturn(1).when(mGlobalSettings)
+ .getIntForUser(Settings.Global.BUGREPORT_IN_POWER_MENU, 0, currentUser.id);
+
+ GlobalActionsDialogLite.BugReportAction bugReportAction =
+ mGlobalActionsDialogLite.makeBugReportActionForTesting();
+ assertThat(bugReportAction.showBeforeProvisioning()).isFalse();
+ }
+
+ private UserInfo mockCurrentUser(int flags) {
+ return new UserInfo(10, "A User", flags);
+
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 798839dcc1f6..804960dc3b18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -168,6 +168,45 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
}
@Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testOnStartedWakingUp_whileSleeping_ifWakeAndUnlocking_doesNotShowKeyguard() {
+ when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+ when(mLockPatternUtils.getPowerButtonInstantlyLocks(anyInt())).thenReturn(true);
+ mViewMediator.onSystemReady();
+ TestableLooper.get(this).processAllMessages();
+
+ mViewMediator.setShowingLocked(false);
+ TestableLooper.get(this).processAllMessages();
+
+ mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
+ mViewMediator.onWakeAndUnlocking();
+ mViewMediator.onStartedWakingUp(OFF_BECAUSE_OF_USER, false);
+ TestableLooper.get(this).processAllMessages();
+
+ assertFalse(mViewMediator.isShowingAndNotOccluded());
+ verify(mKeyguardStateController, never()).notifyKeyguardState(eq(true), anyBoolean());
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testOnStartedWakingUp_whileSleeping_ifNotWakeAndUnlocking_showsKeyguard() {
+ when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+ when(mLockPatternUtils.getPowerButtonInstantlyLocks(anyInt())).thenReturn(true);
+ mViewMediator.onSystemReady();
+ TestableLooper.get(this).processAllMessages();
+
+ mViewMediator.setShowingLocked(false);
+ TestableLooper.get(this).processAllMessages();
+
+ mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
+ mViewMediator.onStartedWakingUp(OFF_BECAUSE_OF_USER, false);
+
+ TestableLooper.get(this).processAllMessages();
+
+ assertTrue(mViewMediator.isShowingAndNotOccluded());
+ }
+
+ @Test
public void testRegisterDumpable() {
verify(mDumpManager).registerDumpable(KeyguardViewMediator.class.getName(), mViewMediator);
verify(mStatusBarKeyguardViewManager, never()).setKeyguardGoingAwayState(anyBoolean());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
new file mode 100644
index 000000000000..9970a6796ed6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.keyguard.ViewMediatorCallback
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableLogBuffer
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardBouncerRepositoryTest : SysuiTestCase() {
+
+ @Mock private lateinit var viewMediatorCallback: ViewMediatorCallback
+ @Mock private lateinit var bouncerLogger: TableLogBuffer
+ lateinit var underTest: KeyguardBouncerRepository
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ val testCoroutineScope = TestCoroutineScope()
+ underTest =
+ KeyguardBouncerRepository(viewMediatorCallback, testCoroutineScope, bouncerLogger)
+ }
+
+ @Test
+ fun changingFlowValueTriggersLogging() = runBlocking {
+ underTest.setPrimaryHide(true)
+ verify(bouncerLogger).logChange("", "PrimaryBouncerHide", false)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index fdef34449adf..b65f5cb51aaf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -214,6 +214,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
private val fakeFeatureFlag =
FakeFeatureFlags().apply {
this.set(Flags.UMO_SURFACE_RIPPLE, false)
+ this.set(Flags.UMO_TURBULENCE_NOISE, false)
this.set(Flags.MEDIA_FALSING_PENALTY, true)
}
@@ -2062,6 +2063,26 @@ public class MediaControlPanelTest : SysuiTestCase() {
assertThat(viewHolder.multiRippleView.ripples.size).isEqualTo(0)
}
+ @Test
+ fun onButtonClick_turbulenceNoiseFlagEnabled_createsRipplesFinishedListener() {
+ fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
+ fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, true)
+
+ player.attachPlayer(viewHolder)
+
+ assertThat(player.mRipplesFinishedListener).isNotNull()
+ }
+
+ @Test
+ fun onButtonClick_turbulenceNoiseFlagDisabled_doesNotCreateRipplesFinishedListener() {
+ fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
+ fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, false)
+
+ player.attachPlayer(viewHolder)
+
+ assertThat(player.mRipplesFinishedListener).isNull()
+ }
+
private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
withArgCaptor {
verify(seekBarViewModel).setScrubbingChangeListener(capture())
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 5c0f0fee096a..7c3c9d2a1bb1 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
@@ -46,6 +46,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -71,10 +72,13 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
private MediaOutputAdapter mMediaOutputAdapter;
private MediaOutputAdapter.MediaDeviceViewHolder mViewHolder;
private List<MediaDevice> mMediaDevices = new ArrayList<>();
+ private List<MediaItem> mMediaItems = new ArrayList<>();
MediaOutputSeekbar mSpyMediaOutputSeekbar;
@Before
public void setUp() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(false);
+ when(mMediaOutputController.getMediaItemList()).thenReturn(mMediaItems);
when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices);
when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false);
when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(false);
@@ -82,7 +86,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat);
when(mMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(mMediaDevice1);
when(mMediaOutputController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(true);
- when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(false);
when(mIconCompat.toIcon(mContext)).thenReturn(mIcon);
when(mMediaDevice1.getName()).thenReturn(TEST_DEVICE_NAME_1);
when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_ID_1);
@@ -94,6 +97,8 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
mMediaDevices.add(mMediaDevice1);
mMediaDevices.add(mMediaDevice2);
+ mMediaItems.add(new MediaItem(mMediaDevice1));
+ mMediaItems.add(new MediaItem(mMediaDevice2));
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
@@ -119,6 +124,26 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
}
@Test
+ public void advanced_getItemCount_returnsMediaItemSize() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaItems.size());
+ }
+
+ @Test
+ public void advanced_getItemId_validPosition_returnCorrespondingId() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ assertThat(mMediaOutputAdapter.getItemId(0)).isEqualTo(mMediaItems.get(
+ 0).getMediaDevice().get().getId().hashCode());
+ }
+
+ @Test
+ public void advanced_getItemId_invalidPosition_returnPosition() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ int invalidPosition = mMediaItems.size() + 1;
+ assertThat(mMediaOutputAdapter.getItemId(invalidPosition)).isEqualTo(invalidPosition);
+ }
+
+ @Test
public void onBindViewHolder_bindPairNew_verifyView() {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
@@ -159,6 +184,63 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
}
@Test
+ public void advanced_onBindViewHolder_bindPairNew_verifyView() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaItems.add(new MediaItem());
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
+
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTitleText.getText()).isEqualTo(mContext.getText(
+ R.string.media_output_dialog_pairing_new));
+ }
+
+ @Test
+ public void advanced_onBindViewHolder_bindGroup_withSessionName_verifyView() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(
+ mMediaItems.stream().map((item) -> item.getMediaDevice().get()).collect(
+ Collectors.toList()));
+ when(mMediaOutputController.getSessionName()).thenReturn(TEST_SESSION_NAME);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.getItemCount();
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void advanced_onBindViewHolder_bindGroup_noSessionName_verifyView() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(
+ mMediaItems.stream().map((item) -> item.getMediaDevice().get()).collect(
+ Collectors.toList()));
+ when(mMediaOutputController.getSessionName()).thenReturn(null);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.getItemCount();
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
public void onBindViewHolder_bindConnectedDevice_verifyView() {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -376,6 +458,19 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
}
@Test
+ public void advanced_onItemClick_clickPairNew_verifyLaunchBluetoothPairing() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaItems.add(new MediaItem());
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
+ mViewHolder.mContainerLayout.performClick();
+
+ verify(mMediaOutputController).launchBluetoothPairing(mViewHolder.mContainerLayout);
+ }
+
+ @Test
public void onItemClick_clickDevice_verifyConnectDevice() {
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
@@ -458,6 +553,26 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
}
@Test
+ public void advanced_onItemClick_onGroupActionTriggered_verifySeekbarDisabled() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(
+ mMediaItems.stream().map((item) -> item.getMediaDevice().get()).collect(
+ Collectors.toList()));
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ List<MediaDevice> selectableDevices = new ArrayList<>();
+ selectableDevices.add(mMediaDevice1);
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(selectableDevices);
+ when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(true);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ mViewHolder.mContainerLayout.performClick();
+
+ assertThat(mViewHolder.mSeekBar.isEnabled()).isFalse();
+ }
+
+ @Test
public void onBindViewHolder_volumeControlChangeToEnabled_enableSeekbarAgain() {
when(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(false);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index c544c0e02d34..71c300c3fb6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -63,6 +63,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -144,6 +145,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager, mFlags);
+ when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(false);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -282,6 +284,25 @@ public class MediaOutputControllerTest extends SysuiTestCase {
}
@Test
+ public void advanced_onDeviceListUpdate_verifyDeviceListCallback() {
+ when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
+ mMediaOutputController.start(mCb);
+ reset(mCb);
+
+ mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ final List<MediaDevice> devices = new ArrayList<>();
+ for (MediaItem item : mMediaOutputController.getMediaItemList()) {
+ if (item.getMediaDevice().isPresent()) {
+ devices.add(item.getMediaDevice().get());
+ }
+ }
+
+ assertThat(devices.containsAll(mMediaDevices)).isTrue();
+ assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+ verify(mCb).onDeviceListChanged();
+ }
+
+ @Test
public void onDeviceListUpdate_isRefreshing_updatesNeedRefreshToTrue() {
mMediaOutputController.start(mCb);
reset(mCb);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
new file mode 100644
index 000000000000..1742c6994246
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
@@ -0,0 +1,93 @@
+package com.android.systemui.navigationbar
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.model.SysUiState
+import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler
+import com.android.systemui.recents.OverviewProxyService
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.phone.AutoHideController
+import com.android.systemui.statusbar.phone.LightBarController
+import com.android.systemui.statusbar.phone.LightBarTransitionsController
+import com.android.wm.shell.back.BackAnimation
+import com.android.wm.shell.pip.Pip
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.Optional
+
+@SmallTest
+class TaskbarDelegateTest : SysuiTestCase() {
+ val DISPLAY_ID = 0;
+ val MODE_GESTURE = 0;
+ val MODE_THREE_BUTTON = 1;
+
+ private lateinit var mTaskbarDelegate: TaskbarDelegate
+ @Mock
+ lateinit var mEdgeBackGestureHandlerFactory : EdgeBackGestureHandler.Factory
+ @Mock
+ lateinit var mEdgeBackGestureHandler : EdgeBackGestureHandler
+ @Mock
+ lateinit var mLightBarControllerFactory : LightBarTransitionsController.Factory
+ @Mock
+ lateinit var mLightBarTransitionController: LightBarTransitionsController
+ @Mock
+ lateinit var mCommandQueue: CommandQueue
+ @Mock
+ lateinit var mOverviewProxyService: OverviewProxyService
+ @Mock
+ lateinit var mNavBarHelper: NavBarHelper
+ @Mock
+ lateinit var mNavigationModeController: NavigationModeController
+ @Mock
+ lateinit var mSysUiState: SysUiState
+ @Mock
+ lateinit var mDumpManager: DumpManager
+ @Mock
+ lateinit var mAutoHideController: AutoHideController
+ @Mock
+ lateinit var mLightBarController: LightBarController
+ @Mock
+ lateinit var mOptionalPip: Optional<Pip>
+ @Mock
+ lateinit var mBackAnimation: BackAnimation
+ @Mock
+ lateinit var mCurrentSysUiState: NavBarHelper.CurrentSysuiState
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(mEdgeBackGestureHandlerFactory.create(context)).thenReturn(mEdgeBackGestureHandler)
+ `when`(mLightBarControllerFactory.create(any())).thenReturn(mLightBarTransitionController)
+ `when`(mNavBarHelper.currentSysuiState).thenReturn(mCurrentSysUiState)
+ `when`(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState)
+ mTaskbarDelegate = TaskbarDelegate(context, mEdgeBackGestureHandlerFactory,
+ mLightBarControllerFactory)
+ mTaskbarDelegate.setDependencies(mCommandQueue, mOverviewProxyService, mNavBarHelper,
+ mNavigationModeController, mSysUiState, mDumpManager, mAutoHideController,
+ mLightBarController, mOptionalPip, mBackAnimation)
+ }
+
+ @Test
+ fun navigationModeInitialized() {
+ `when`(mNavigationModeController.addListener(any())).thenReturn(MODE_THREE_BUTTON)
+ assert(mTaskbarDelegate.navigationMode == -1)
+ mTaskbarDelegate.init(DISPLAY_ID)
+ assert(mTaskbarDelegate.navigationMode == MODE_THREE_BUTTON)
+ }
+
+ @Test
+ fun navigationModeInitialized_notifyEdgeBackHandler() {
+ `when`(mNavigationModeController.addListener(any())).thenReturn(MODE_GESTURE)
+ mTaskbarDelegate.init(DISPLAY_ID)
+ verify(mEdgeBackGestureHandler, times(1)).onNavigationModeChanged(MODE_GESTURE)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index 9f28708a388e..5e082f686ea3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -1,9 +1,12 @@
package com.android.systemui.qs
+import android.content.res.Configuration
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
+import android.testing.TestableResources
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
@@ -26,10 +29,11 @@ import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.any
+import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -54,8 +58,11 @@ class QSPanelControllerTest : SysuiTestCase() {
@Mock private lateinit var otherTile: QSTile
@Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
@Mock private lateinit var featureFlags: FeatureFlags
+ @Mock private lateinit var configuration: Configuration
+ @Mock private lateinit var pagedTileLayout: PagedTileLayout
private lateinit var controller: QSPanelController
+ private val testableResources: TestableResources = mContext.orCreateTestableResources
@Before
fun setUp() {
@@ -63,7 +70,9 @@ class QSPanelControllerTest : SysuiTestCase() {
whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider)
whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController)
- whenever(qsPanel.resources).thenReturn(mContext.orCreateTestableResources.resources)
+ testableResources.addOverride(R.bool.config_use_split_notification_shade, false)
+ whenever(qsPanel.resources).thenReturn(testableResources.resources)
+ whenever(qsPanel.getOrCreateTileLayout()).thenReturn(pagedTileLayout)
whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false)
whenever(qsPanel.setListening(anyBoolean())).then {
whenever(qsPanel.isListening).thenReturn(it.getArgument(0))
@@ -121,4 +130,15 @@ class QSPanelControllerTest : SysuiTestCase() {
whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false)
assertThat(controller.isBouncerInTransit()).isEqualTo(false)
}
+
+ @Test
+ fun configurationChange_onlySplitShadeConfigChanges_tileAreRedistributed() {
+ testableResources.addOverride(R.bool.config_use_split_notification_shade, false)
+ controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
+ verify(pagedTileLayout, never()).forceTilesRedistribution()
+
+ testableResources.addOverride(R.bool.config_use_split_notification_shade, true)
+ controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
+ verify(pagedTileLayout).forceTilesRedistribution()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index c656d6dd1a35..88d7e9cb4de4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -40,6 +40,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.os.Looper;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -115,6 +116,10 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this);
Looper looper = mTestableLooper.getLooper();
Handler mainHandler = new Handler(looper);
+ // TODO(b/259908270): remove
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
+ /* makeDefault= */ false);
when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
mFooterUtils = new QSSecurityFooterUtils(getContext(),
getContext().getSystemService(DevicePolicyManager.class), mUserTracker,
@@ -122,6 +127,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.getDeviceOwnerComponentOnAnyUser())
.thenReturn(DEVICE_OWNER_COMPONENT);
+ when(mSecurityController.isFinancedDevice()).thenReturn(false);
+ // TODO(b/259908270): remove
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
}
@@ -184,6 +191,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.isDeviceManaged()).thenReturn(true);
when(mSecurityController.getDeviceOwnerOrganizationName())
.thenReturn(MANAGING_ORGANIZATION);
+ when(mSecurityController.isFinancedDevice()).thenReturn(true);
+ // TODO(b/259908270): remove
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
@@ -495,6 +504,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
@Test
public void testGetManagementTitleForFinancedDevice() {
when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ when(mSecurityController.isFinancedDevice()).thenReturn(true);
+ // TODO(b/259908270): remove
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
@@ -524,6 +535,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
@Test
public void testGetManagementMessage_deviceOwner_asFinancedDevice() {
when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ when(mSecurityController.isFinancedDevice()).thenReturn(true);
+ // TODO(b/259908270): remove
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
@@ -689,6 +702,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.isDeviceManaged()).thenReturn(true);
when(mSecurityController.getDeviceOwnerOrganizationName())
.thenReturn(MANAGING_ORGANIZATION);
+ when(mSecurityController.isFinancedDevice()).thenReturn(true);
+ // TODO(b/259908270): remove
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
@@ -711,6 +726,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.isDeviceManaged()).thenReturn(true);
when(mSecurityController.getDeviceOwnerOrganizationName())
.thenReturn(MANAGING_ORGANIZATION);
+ when(mSecurityController.isFinancedDevice()).thenReturn(true);
+ // TODO(b/259908270): remove
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index c8a392b11363..63065a52bd3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -75,6 +75,7 @@ import android.os.BatteryManager;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.ViewGroup;
@@ -217,6 +218,10 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mTextView = new KeyguardIndicationTextView(mContext);
mTextView.setAnimationsEnabled(false);
+ // TODO(b/259908270): remove
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
+ /* makeDefault= */ false);
mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
mContext.addMockSystemService(UserManager.class, mUserManager);
mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
@@ -238,8 +243,12 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
.thenReturn(DEVICE_OWNER_COMPONENT);
+ when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false);
+ // TODO(b/259908270): remove
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
+
+
when(mDevicePolicyResourcesManager.getString(anyString(), any()))
.thenReturn(mDisclosureGeneric);
when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
@@ -489,6 +498,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+ when(mDevicePolicyManager.isFinancedDevice()).thenReturn(true);
+ // TODO(b/259908270): remove
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
sendUpdateDisclosureBroadcast();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index 7f73856bff89..5f19fac8666a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator
+import android.app.Notification
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -33,6 +34,7 @@ import com.android.systemui.statusbar.notification.collection.provider.SectionHe
import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider
import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
@@ -105,6 +107,50 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
}
@Test
+ fun unseenFilterDoesNotSuppressSeenOngoingNotifWhileKeyguardShowing() {
+ whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
+
+ // GIVEN: Keyguard is not showing, and an ongoing notification is present
+ keyguardRepository.setKeyguardShowing(false)
+ runKeyguardCoordinatorTest {
+ val fakeEntry = NotificationEntryBuilder()
+ .setNotification(Notification.Builder(mContext).setOngoing(true).build())
+ .build()
+ collectionListener.onEntryAdded(fakeEntry)
+
+ // WHEN: The keyguard is now showing
+ keyguardRepository.setKeyguardShowing(true)
+ testScheduler.runCurrent()
+
+ // THEN: The notification is recognized as "ongoing" and is not filtered out.
+ assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse()
+ }
+ }
+
+ @Test
+ fun unseenFilterDoesNotSuppressSeenMediaNotifWhileKeyguardShowing() {
+ whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
+
+ // GIVEN: Keyguard is not showing, and a media notification is present
+ keyguardRepository.setKeyguardShowing(false)
+ runKeyguardCoordinatorTest {
+ val fakeEntry = NotificationEntryBuilder().build().apply {
+ row = mock<ExpandableNotificationRow>().apply {
+ whenever(isMediaRow).thenReturn(true)
+ }
+ }
+ collectionListener.onEntryAdded(fakeEntry)
+
+ // WHEN: The keyguard is now showing
+ keyguardRepository.setKeyguardShowing(true)
+ testScheduler.runCurrent()
+
+ // THEN: The notification is recognized as "media" and is not filtered out.
+ assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse()
+ }
+ }
+
+ @Test
fun unseenFilterUpdatesSeenProviderWhenSuppressing() {
whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 21aae00f12ba..601771d64046 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -23,6 +23,7 @@ import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
@@ -61,6 +62,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -527,6 +529,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mDreamManager.isDreaming()).thenReturn(false);
when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.NO_FULL_SCREEN_INTENT);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isFalse();
verify(mLogger, never()).logNoFullscreen(any(), any());
@@ -535,6 +539,44 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
}
@Test
+ public void testShouldNotFullScreen_suppressedOnlyByDND() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ modifyRanking(entry)
+ .setSuppressedVisualEffects(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT)
+ .build();
+ when(mPowerManager.isInteractive()).thenReturn(false);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND);
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ verify(mLogger, never()).logFullscreen(any(), any());
+ verify(mLogger, never()).logNoFullscreenWarning(any(), any());
+ verify(mLogger).logNoFullscreen(entry, "Suppressed by DND");
+ }
+
+ @Test
+ public void testShouldNotFullScreen_suppressedByDNDAndOther() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_LOW, /* silenced */ false);
+ modifyRanking(entry)
+ .setSuppressedVisualEffects(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT)
+ .build();
+ when(mPowerManager.isInteractive()).thenReturn(false);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_SUPPRESSED_BY_DND);
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ verify(mLogger, never()).logFullscreen(any(), any());
+ verify(mLogger, never()).logNoFullscreenWarning(any(), any());
+ verify(mLogger).logNoFullscreen(entry, "Suppressed by DND");
+ }
+
+ @Test
public void testShouldNotFullScreen_notHighImportance_withStrictFlag() throws Exception {
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
testShouldNotFullScreen_notHighImportance();
@@ -547,6 +589,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mDreamManager.isDreaming()).thenReturn(false);
when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_NOT_IMPORTANT_ENOUGH);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isFalse();
verify(mLogger).logNoFullscreen(entry, "Not important enough");
@@ -567,6 +611,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mDreamManager.isDreaming()).thenReturn(true);
when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isFalse();
verify(mLogger, never()).logNoFullscreen(any(), any());
@@ -594,6 +640,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mDreamManager.isDreaming()).thenReturn(false);
when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isTrue();
verify(mLogger, never()).logNoFullscreen(any(), any());
@@ -614,6 +662,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mDreamManager.isDreaming()).thenReturn(true);
when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.FSI_DEVICE_IS_DREAMING);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isTrue();
verify(mLogger, never()).logNoFullscreen(any(), any());
@@ -634,6 +684,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mDreamManager.isDreaming()).thenReturn(false);
when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.FSI_KEYGUARD_SHOWING);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isTrue();
verify(mLogger, never()).logNoFullscreen(any(), any());
@@ -655,6 +707,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mDreamManager.isDreaming()).thenReturn(false);
when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isFalse();
verify(mLogger).logNoFullscreen(entry, "Expected to HUN");
@@ -671,9 +725,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mStatusBarStateController.getState()).thenReturn(SHADE);
when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.FSI_EXPECTED_NOT_TO_HUN);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isTrue();
- verify(mLogger).logNoHeadsUpPackageSnoozed(entry);
verify(mLogger, never()).logNoFullscreen(any(), any());
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
verify(mLogger).logFullscreen(entry, "Expected not to HUN");
@@ -691,9 +746,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isOccluded()).thenReturn(true);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.FSI_KEYGUARD_OCCLUDED);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isTrue();
- verify(mLogger).logNoHeadsUpPackageSnoozed(entry);
verify(mLogger, never()).logNoFullscreen(any(), any());
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
verify(mLogger).logFullscreen(entry, "Expected not to HUN while keyguard occluded");
@@ -711,9 +767,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isOccluded()).thenReturn(false);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.FSI_LOCKED_SHADE);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isTrue();
- verify(mLogger).logNoHeadsUpPackageSnoozed(entry);
verify(mLogger, never()).logNoFullscreen(any(), any());
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
verify(mLogger).logFullscreen(entry, "Keyguard is showing and not occluded");
@@ -731,9 +788,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mKeyguardStateController.isShowing()).thenReturn(false);
when(mKeyguardStateController.isOccluded()).thenReturn(false);
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isFalse();
- verify(mLogger).logNoHeadsUpPackageSnoozed(entry);
verify(mLogger, never()).logNoFullscreen(any(), any());
verify(mLogger).logNoFullscreenWarning(entry, "Expected not to HUN while not on keyguard");
verify(mLogger, never()).logFullscreen(any(), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 9727b6c5eb83..e5e5d94ab595 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
@@ -33,12 +35,14 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
@@ -64,7 +68,9 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mock(NotificationPanelViewController.class);
private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private ExpandableNotificationRow mFirst;
+ private NotificationTestHelper mTestHelper;
+ private ExpandableNotificationRow mRow;
+ private NotificationEntry mEntry;
private HeadsUpStatusBarView mHeadsUpStatusBarView;
private HeadsUpManagerPhone mHeadsUpManager;
private View mOperatorNameView;
@@ -79,11 +85,12 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
allowTestableLooperAsMainThread();
- NotificationTestHelper testHelper = new NotificationTestHelper(
+ mTestHelper = new NotificationTestHelper(
mContext,
mDependency,
TestableLooper.get(this));
- mFirst = testHelper.createRow();
+ mRow = mTestHelper.createRow();
+ mEntry = mRow.getEntry();
mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
mock(TextView.class));
mHeadsUpManager = mock(HeadsUpManagerPhone.class);
@@ -95,6 +102,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mCommandQueue = mock(CommandQueue.class);
mNotificationRoundnessManager = mock(NotificationRoundnessManager.class);
mFeatureFlag = mock(FeatureFlags.class);
+ when(mFeatureFlag.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)).thenReturn(true);
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mock(NotificationIconAreaController.class),
mHeadsUpManager,
@@ -116,60 +124,60 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
@Test
public void testShowinEntryUpdated() {
- mFirst.setPinned(true);
+ mRow.setPinned(true);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
- mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry());
- Assert.assertEquals(mFirst.getEntry(), mHeadsUpStatusBarView.getShowingEntry());
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
+ mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
+ assertEquals(mRow.getEntry(), mHeadsUpStatusBarView.getShowingEntry());
- mFirst.setPinned(false);
+ mRow.setPinned(false);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry());
- Assert.assertEquals(null, mHeadsUpStatusBarView.getShowingEntry());
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
+ assertEquals(null, mHeadsUpStatusBarView.getShowingEntry());
}
@Test
public void testShownUpdated() {
- mFirst.setPinned(true);
+ mRow.setPinned(true);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
- mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry());
- Assert.assertTrue(mHeadsUpAppearanceController.isShown());
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
+ mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
+ assertTrue(mHeadsUpAppearanceController.isShown());
- mFirst.setPinned(false);
+ mRow.setPinned(false);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
Assert.assertFalse(mHeadsUpAppearanceController.isShown());
}
@Test
public void testHeaderUpdated() {
- mFirst.setPinned(true);
+ mRow.setPinned(true);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
- mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry());
- Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 0.0f, 0.0f);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
+ mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
+ assertEquals(mRow.getHeaderVisibleAmount(), 0.0f, 0.0f);
- mFirst.setPinned(false);
+ mRow.setPinned(false);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry());
- Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 1.0f, 0.0f);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
+ assertEquals(mRow.getHeaderVisibleAmount(), 1.0f, 0.0f);
}
@Test
public void testOperatorNameViewUpdated() {
mHeadsUpAppearanceController.setAnimationsEnabled(false);
- mFirst.setPinned(true);
+ mRow.setPinned(true);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
- mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry());
- Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
+ mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
+ assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
- mFirst.setPinned(false);
+ mRow.setPinned(false);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry());
- Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
+ assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
}
@Test
@@ -196,8 +204,8 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
new Clock(mContext, null),
Optional.empty());
- Assert.assertEquals(expandedHeight, newController.mExpandedHeight, 0.0f);
- Assert.assertEquals(appearFraction, newController.mAppearFraction, 0.0f);
+ assertEquals(expandedHeight, newController.mExpandedHeight, 0.0f);
+ assertEquals(appearFraction, newController.mAppearFraction, 0.0f);
}
@Test
@@ -215,4 +223,68 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
verify(mPanelView).setHeadsUpAppearanceController(isNull());
verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
}
+
+ @Test
+ public void testPulsingRoundness_onUpdateHeadsUpAndPulsingRoundness() {
+ // Pulsing: Enable flag and dozing
+ when(mNotificationRoundnessManager.shouldRoundNotificationPulsing()).thenReturn(true);
+ when(mTestHelper.getStatusBarStateController().isDozing()).thenReturn(true);
+
+ // Pulsing: Enabled
+ mRow.setHeadsUp(true);
+ mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(mEntry);
+
+ String debugString = mRow.getRoundableState().debugString();
+ assertEquals(
+ "If Pulsing is enabled, roundness should be set to 1. Value: " + debugString,
+ /* expected = */ 1,
+ /* actual = */ mRow.getTopRoundness(),
+ /* delta = */ 0.001
+ );
+ assertTrue(debugString.contains("Pulsing"));
+
+ // Pulsing: Disabled
+ mRow.setHeadsUp(false);
+ mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(mEntry);
+
+ assertEquals(
+ "If Pulsing is disabled, roundness should be set to 0. Value: "
+ + mRow.getRoundableState().debugString(),
+ /* expected = */ 0,
+ /* actual = */ mRow.getTopRoundness(),
+ /* delta = */ 0.001
+ );
+ }
+
+ @Test
+ public void testPulsingRoundness_onHeadsUpStateChanged() {
+ // Pulsing: Enable flag and dozing
+ when(mNotificationRoundnessManager.shouldRoundNotificationPulsing()).thenReturn(true);
+ when(mTestHelper.getStatusBarStateController().isDozing()).thenReturn(true);
+
+ // Pulsing: Enabled
+ mEntry.setHeadsUp(true);
+ mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, true);
+
+ String debugString = mRow.getRoundableState().debugString();
+ assertEquals(
+ "If Pulsing is enabled, roundness should be set to 1. Value: " + debugString,
+ /* expected = */ 1,
+ /* actual = */ mRow.getTopRoundness(),
+ /* delta = */ 0.001
+ );
+ assertTrue(debugString.contains("Pulsing"));
+
+ // Pulsing: Disabled
+ mEntry.setHeadsUp(false);
+ mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, false);
+
+ assertEquals(
+ "If Pulsing is disabled, roundness should be set to 0. Value: "
+ + mRow.getRoundableState().debugString(),
+ /* expected = */ 0,
+ /* actual = */ mRow.getTopRoundness(),
+ /* delta = */ 0.001
+ );
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 15235b68c881..c35bc69bf15b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -149,11 +149,12 @@ public class SecurityControllerTest extends SysuiTestCase {
}
@Test
- public void testGetDeviceOwnerType() {
+ public void testIsFinancedDevice() {
+ when(mDevicePolicyManager.isFinancedDevice()).thenReturn(true);
+ // TODO(b/259908270): remove
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
- assertEquals(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT),
- DEVICE_OWNER_TYPE_FINANCED);
+ assertEquals(mSecurityController.isFinancedDevice(), true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
new file mode 100644
index 000000000000..58b55602a39c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.stylus
+
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.hardware.input.InputManager
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.view.InputDevice
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@Ignore("b/257936830 until bt APIs")
+class StylusManagerTest : SysuiTestCase() {
+ @Mock lateinit var inputManager: InputManager
+
+ @Mock lateinit var stylusDevice: InputDevice
+
+ @Mock lateinit var btStylusDevice: InputDevice
+
+ @Mock lateinit var otherDevice: InputDevice
+
+ @Mock lateinit var bluetoothAdapter: BluetoothAdapter
+
+ @Mock lateinit var bluetoothDevice: BluetoothDevice
+
+ @Mock lateinit var handler: Handler
+
+ @Mock lateinit var stylusCallback: StylusManager.StylusCallback
+
+ @Mock lateinit var otherStylusCallback: StylusManager.StylusCallback
+
+ @Mock lateinit var stylusBatteryCallback: StylusManager.StylusBatteryCallback
+
+ @Mock lateinit var otherStylusBatteryCallback: StylusManager.StylusBatteryCallback
+
+ private lateinit var stylusManager: StylusManager
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(handler.post(any())).thenAnswer {
+ (it.arguments[0] as Runnable).run()
+ true
+ }
+
+ stylusManager = StylusManager(inputManager, bluetoothAdapter, handler, EXECUTOR)
+
+ stylusManager.registerCallback(stylusCallback)
+
+ stylusManager.registerBatteryCallback(stylusBatteryCallback)
+
+ whenever(otherDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(false)
+ whenever(stylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
+ whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
+
+ // whenever(stylusDevice.bluetoothAddress).thenReturn(null)
+ // whenever(btStylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+
+ whenever(inputManager.getInputDevice(OTHER_DEVICE_ID)).thenReturn(otherDevice)
+ whenever(inputManager.getInputDevice(STYLUS_DEVICE_ID)).thenReturn(stylusDevice)
+ whenever(inputManager.getInputDevice(BT_STYLUS_DEVICE_ID)).thenReturn(btStylusDevice)
+ whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(STYLUS_DEVICE_ID))
+
+ whenever(bluetoothAdapter.getRemoteDevice(STYLUS_BT_ADDRESS)).thenReturn(bluetoothDevice)
+ whenever(bluetoothDevice.address).thenReturn(STYLUS_BT_ADDRESS)
+ }
+
+ @Test
+ fun startListener_registersInputDeviceListener() {
+ stylusManager.startListener()
+
+ verify(inputManager, times(1)).registerInputDeviceListener(any(), any())
+ }
+
+ @Test
+ fun onInputDeviceAdded_multipleRegisteredCallbacks_callsAll() {
+ stylusManager.registerCallback(otherStylusCallback)
+
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1)).onStylusAdded(STYLUS_DEVICE_ID)
+ verifyNoMoreInteractions(stylusCallback)
+ verify(otherStylusCallback, times(1)).onStylusAdded(STYLUS_DEVICE_ID)
+ verifyNoMoreInteractions(otherStylusCallback)
+ }
+
+ @Test
+ fun onInputDeviceAdded_stylus_callsCallbacksOnStylusAdded() {
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1)).onStylusAdded(STYLUS_DEVICE_ID)
+ verifyNoMoreInteractions(stylusCallback)
+ }
+
+ @Test
+ fun onInputDeviceAdded_btStylus_callsCallbacksWithAddress() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ inOrder(stylusCallback).let {
+ it.verify(stylusCallback, times(1)).onStylusAdded(BT_STYLUS_DEVICE_ID)
+ it.verify(stylusCallback, times(1))
+ .onStylusBluetoothConnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS)
+ }
+ }
+
+ @Test
+ fun onInputDeviceAdded_notStylus_doesNotCallCallbacks() {
+ stylusManager.onInputDeviceAdded(OTHER_DEVICE_ID)
+
+ verifyNoMoreInteractions(stylusCallback)
+ }
+
+ @Test
+ fun onInputDeviceChanged_multipleRegisteredCallbacks_callsAll() {
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+ // whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+ stylusManager.registerCallback(otherStylusCallback)
+
+ stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1))
+ .onStylusBluetoothConnected(STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS)
+ verify(otherStylusCallback, times(1))
+ .onStylusBluetoothConnected(STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS)
+ }
+
+ @Test
+ fun onInputDeviceChanged_stylusNewBtConnection_callsCallbacks() {
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+ // whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+
+ stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1))
+ .onStylusBluetoothConnected(STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS)
+ }
+
+ @Test
+ fun onInputDeviceChanged_stylusLostBtConnection_callsCallbacks() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+ // whenever(btStylusDevice.bluetoothAddress).thenReturn(null)
+
+ stylusManager.onInputDeviceChanged(BT_STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1))
+ .onStylusBluetoothDisconnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS)
+ }
+
+ @Test
+ fun onInputDeviceChanged_btConnection_stylusAlreadyBtConnected_onlyCallsListenersOnce() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ stylusManager.onInputDeviceChanged(BT_STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1))
+ .onStylusBluetoothConnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS)
+ }
+
+ @Test
+ fun onInputDeviceChanged_noBtConnection_stylusNeverBtConnected_doesNotCallCallbacks() {
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, never()).onStylusBluetoothDisconnected(any(), any())
+ }
+
+ @Test
+ fun onInputDeviceRemoved_multipleRegisteredCallbacks_callsAll() {
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+ stylusManager.registerCallback(otherStylusCallback)
+
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1)).onStylusRemoved(STYLUS_DEVICE_ID)
+ verify(otherStylusCallback, times(1)).onStylusRemoved(STYLUS_DEVICE_ID)
+ }
+
+ @Test
+ fun onInputDeviceRemoved_stylus_callsCallbacks() {
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ stylusManager.onInputDeviceRemoved(STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1)).onStylusRemoved(STYLUS_DEVICE_ID)
+ verify(stylusCallback, never()).onStylusBluetoothDisconnected(any(), any())
+ }
+
+ @Test
+ fun onInputDeviceRemoved_btStylus_callsCallbacks() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ stylusManager.onInputDeviceRemoved(BT_STYLUS_DEVICE_ID)
+
+ inOrder(stylusCallback).let {
+ it.verify(stylusCallback, times(1))
+ .onStylusBluetoothDisconnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS)
+ it.verify(stylusCallback, times(1)).onStylusRemoved(BT_STYLUS_DEVICE_ID)
+ }
+ }
+
+ @Test
+ fun onStylusBluetoothConnected_registersMetadataListener() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ verify(bluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any())
+ }
+
+ @Test
+ fun onStylusBluetoothConnected_noBluetoothDevice_doesNotRegisterMetadataListener() {
+ whenever(bluetoothAdapter.getRemoteDevice(STYLUS_BT_ADDRESS)).thenReturn(null)
+
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ verify(bluetoothAdapter, never()).addOnMetadataChangedListener(any(), any(), any())
+ }
+
+ @Test
+ fun onStylusBluetoothDisconnected_unregistersMetadataListener() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ stylusManager.onInputDeviceRemoved(BT_STYLUS_DEVICE_ID)
+
+ verify(bluetoothAdapter, times(1)).removeOnMetadataChangedListener(any(), any())
+ }
+
+ @Test
+ fun onMetadataChanged_multipleRegisteredBatteryCallbacks_executesAll() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+ stylusManager.registerBatteryCallback(otherStylusBatteryCallback)
+
+ stylusManager.onMetadataChanged(
+ bluetoothDevice,
+ BluetoothDevice.METADATA_MAIN_CHARGING,
+ "true".toByteArray()
+ )
+
+ verify(stylusBatteryCallback, times(1))
+ .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, true)
+ verify(otherStylusBatteryCallback, times(1))
+ .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, true)
+ }
+
+ @Test
+ fun onMetadataChanged_chargingStateTrue_executesBatteryCallbacks() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ stylusManager.onMetadataChanged(
+ bluetoothDevice,
+ BluetoothDevice.METADATA_MAIN_CHARGING,
+ "true".toByteArray()
+ )
+
+ verify(stylusBatteryCallback, times(1))
+ .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, true)
+ }
+
+ @Test
+ fun onMetadataChanged_chargingStateFalse_executesBatteryCallbacks() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ stylusManager.onMetadataChanged(
+ bluetoothDevice,
+ BluetoothDevice.METADATA_MAIN_CHARGING,
+ "false".toByteArray()
+ )
+
+ verify(stylusBatteryCallback, times(1))
+ .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, false)
+ }
+
+ @Test
+ fun onMetadataChanged_chargingStateNoDevice_doesNotExecuteBatteryCallbacks() {
+ stylusManager.onMetadataChanged(
+ bluetoothDevice,
+ BluetoothDevice.METADATA_MAIN_CHARGING,
+ "true".toByteArray()
+ )
+
+ verifyNoMoreInteractions(stylusBatteryCallback)
+ }
+
+ @Test
+ fun onMetadataChanged_notChargingState_doesNotExecuteBatteryCallbacks() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ stylusManager.onMetadataChanged(
+ bluetoothDevice,
+ BluetoothDevice.METADATA_DEVICE_TYPE,
+ "true".toByteArray()
+ )
+
+ verify(stylusBatteryCallback, never())
+ .onStylusBluetoothChargingStateChanged(any(), any(), any())
+ }
+
+ companion object {
+ private val EXECUTOR = Executor { r -> r.run() }
+
+ private const val OTHER_DEVICE_ID = 0
+ private const val STYLUS_DEVICE_ID = 1
+ private const val BT_STYLUS_DEVICE_ID = 2
+
+ private const val STYLUS_BT_ADDRESS = "SOME:ADDRESS"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
index 0d19ab1db390..056e3863f70e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
@@ -101,4 +101,52 @@ class MultiRippleControllerTest : SysuiTestCase() {
assertThat(multiRippleView.ripples.size).isEqualTo(0)
}
}
+
+ @Test
+ fun play_onFinishesAllRipples_triggersRipplesFinished() {
+ var isTriggered = false
+ val listener =
+ object : MultiRippleController.Companion.RipplesFinishedListener {
+ override fun onRipplesFinish() {
+ isTriggered = true
+ }
+ }
+ multiRippleController.addRipplesFinishedListener(listener)
+
+ fakeExecutor.execute {
+ multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 1000)))
+ multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 2000)))
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(2)
+
+ fakeSystemClock.advanceTime(2000L)
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(0)
+ assertThat(isTriggered).isTrue()
+ }
+ }
+
+ @Test
+ fun play_notAllRipplesFinished_doesNotTriggerRipplesFinished() {
+ var isTriggered = false
+ val listener =
+ object : MultiRippleController.Companion.RipplesFinishedListener {
+ override fun onRipplesFinish() {
+ isTriggered = true
+ }
+ }
+ multiRippleController.addRipplesFinishedListener(listener)
+
+ fakeExecutor.execute {
+ multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 1000)))
+ multiRippleController.play(RippleAnimation(RippleAnimationConfig(duration = 2000)))
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(2)
+
+ fakeSystemClock.advanceTime(1000L)
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(1)
+ assertThat(isTriggered).isFalse()
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleViewTest.kt
deleted file mode 100644
index 2024d53b0212..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleViewTest.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.surfaceeffects.ripple
-
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class MultiRippleViewTest : SysuiTestCase() {
- private val fakeSystemClock = FakeSystemClock()
- // FakeExecutor is needed to run animator.
- private val fakeExecutor = FakeExecutor(fakeSystemClock)
-
- @Test
- fun onRippleFinishes_triggersRippleFinished() {
- val multiRippleView = MultiRippleView(context, null)
- val multiRippleController = MultiRippleController(multiRippleView)
- val rippleAnimationConfig = RippleAnimationConfig(duration = 1000L)
-
- var isTriggered = false
- val listener =
- object : MultiRippleView.Companion.RipplesFinishedListener {
- override fun onRipplesFinish() {
- isTriggered = true
- }
- }
- multiRippleView.addRipplesFinishedListener(listener)
-
- fakeExecutor.execute {
- val rippleAnimation = RippleAnimation(rippleAnimationConfig)
- multiRippleController.play(rippleAnimation)
-
- fakeSystemClock.advanceTime(rippleAnimationConfig.duration)
-
- assertThat(isTriggered).isTrue()
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
index 03fd624a8c1d..abbdab0d41f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
@@ -69,6 +69,22 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
}
@Test
+ fun testUnfold_emitsFinishingEvent() {
+ runOnMainThreadWithInterval(
+ { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
+ { foldStateProvider.sendHingeAngleUpdate(10f) },
+ { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+ { foldStateProvider.sendHingeAngleUpdate(90f) },
+ { foldStateProvider.sendHingeAngleUpdate(180f) },
+ { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
+ )
+
+ with(listener.ensureTransitionFinished()) {
+ assertHasSingleFinishingEvent()
+ }
+ }
+
+ @Test
fun testUnfold_screenAvailableOnlyAfterFullUnfold_emitsIncreasingTransitionEvents() {
runOnMainThreadWithInterval(
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
@@ -157,6 +173,12 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
currentRecording!!.addProgress(progress)
}
+ override fun onTransitionFinishing() {
+ assertWithMessage("Received transition finishing event when it's not started")
+ .that(currentRecording).isNotNull()
+ currentRecording!!.onFinishing()
+ }
+
override fun onTransitionFinished() {
assertWithMessage("Received transition finish event when it's not started")
.that(currentRecording).isNotNull()
@@ -171,6 +193,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
class UnfoldTransitionRecording {
private val progressHistory: MutableList<Float> = arrayListOf()
+ private var finishingInvocations: Int = 0
fun addProgress(progress: Float) {
assertThat(progress).isAtMost(1.0f)
@@ -179,6 +202,10 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
progressHistory += progress
}
+ fun onFinishing() {
+ finishingInvocations++
+ }
+
fun assertIncreasingProgress() {
assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS)
assertThat(progressHistory).isInOrder()
@@ -206,6 +233,11 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
.isInOrder(Comparator.reverseOrder<Float>())
assertThat(progressHistory.last()).isEqualTo(0.0f)
}
+
+ fun assertHasSingleFinishingEvent() {
+ assertWithMessage("onTransitionFinishing callback should be invoked exactly " +
+ "one time").that(finishingInvocations).isEqualTo(1)
+ }
}
private companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index 5beb2b389349..ffa4e2d8f158 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -52,6 +52,7 @@ import com.android.systemui.user.data.source.UserRecord
import com.android.systemui.user.domain.model.ShowDialogRequestModel
import com.android.systemui.user.shared.model.UserActionModel
import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.user.utils.MultiUserActionsEvent
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
@@ -74,6 +75,7 @@ import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -158,6 +160,7 @@ class UserInteractorTest : SysuiTestCase() {
resumeSessionReceiver = resumeSessionReceiver,
resetOrExitSessionReceiver = resetOrExitSessionReceiver,
),
+ uiEventLogger = uiEventLogger,
featureFlags = featureFlags,
)
}
@@ -457,6 +460,9 @@ class UserInteractorTest : SysuiTestCase() {
val dialogShower: UserSwitchDialogController.DialogShower = mock()
underTest.executeAction(UserActionModel.ADD_USER, dialogShower)
+
+ verify(uiEventLogger, times(1))
+ .log(MultiUserActionsEvent.CREATE_USER_FROM_USER_SWITCHER)
assertThat(dialogRequest)
.isEqualTo(
ShowDialogRequestModel.ShowAddUserDialog(
@@ -478,6 +484,8 @@ class UserInteractorTest : SysuiTestCase() {
runBlocking(IMMEDIATE) {
underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
+ verify(uiEventLogger, times(1))
+ .log(MultiUserActionsEvent.CREATE_RESTRICTED_USER_FROM_USER_SWITCHER)
val intentCaptor = kotlinArgumentCaptor<Intent>()
verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
assertThat(intentCaptor.value.action)
@@ -525,6 +533,8 @@ class UserInteractorTest : SysuiTestCase() {
underTest.executeAction(UserActionModel.ENTER_GUEST_MODE)
+ verify(uiEventLogger, times(1))
+ .log(MultiUserActionsEvent.CREATE_GUEST_FROM_USER_SWITCHER)
assertThat(dialogRequests)
.contains(
ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 108fa6246e9c..5d4c1cc163d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -255,6 +255,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
activityManager = activityManager,
refreshUsersScheduler = refreshUsersScheduler,
guestUserInteractor = guestUserInteractor,
+ uiEventLogger = uiEventLogger,
)
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 784a26bb371b..0efede1c2a1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -158,6 +158,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
activityManager = activityManager,
refreshUsersScheduler = refreshUsersScheduler,
guestUserInteractor = guestUserInteractor,
+ uiEventLogger = uiEventLogger,
),
powerInteractor =
PowerInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index a0b4eab1d5df..c3c6975af870 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -45,6 +45,7 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.VolumeDialogController;
@@ -98,6 +99,8 @@ public class VolumeDialogImplTest extends SysuiTestCase {
ActivityStarter mActivityStarter;
@Mock
InteractionJankMonitor mInteractionJankMonitor;
+ @Mock
+ private DumpManager mDumpManager;
@Before
public void setup() throws Exception {
@@ -119,7 +122,9 @@ public class VolumeDialogImplTest extends SysuiTestCase {
mActivityStarter,
mInteractionJankMonitor,
mDeviceConfigProxy,
- mExecutor);
+ mExecutor,
+ mDumpManager
+ );
mDialog.init(0, null);
State state = createShellState();
mDialog.onStateChangedH(state);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 30dc0d20600f..0fdcb95b3eed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -19,15 +19,13 @@ package com.android.systemui.wallpapers;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.equalTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -36,19 +34,13 @@ import static org.mockito.hamcrest.MockitoHamcrest.intThat;
import android.app.WallpaperManager;
import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
-import android.os.Handler;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.Display;
-import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager;
@@ -57,28 +49,21 @@ import android.view.WindowMetrics;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.concurrent.CountDownLatch;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class ImageWallpaperTest extends SysuiTestCase {
private static final int LOW_BMP_WIDTH = 128;
private static final int LOW_BMP_HEIGHT = 128;
- private static final int INVALID_BMP_WIDTH = 1;
- private static final int INVALID_BMP_HEIGHT = 1;
private static final int DISPLAY_WIDTH = 1920;
private static final int DISPLAY_HEIGHT = 1080;
@@ -99,19 +84,9 @@ public class ImageWallpaperTest extends SysuiTestCase {
@Mock
private Bitmap mWallpaperBitmap;
- private int mBitmapWidth = 1;
- private int mBitmapHeight = 1;
-
- @Mock
- private Handler mHandler;
- @Mock
- private FeatureFlags mFeatureFlags;
-
FakeSystemClock mFakeSystemClock = new FakeSystemClock();
FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock);
- private CountDownLatch mEventCountdown;
-
@Before
public void setUp() throws Exception {
allowTestableLooperAsMainThread();
@@ -131,12 +106,8 @@ public class ImageWallpaperTest extends SysuiTestCase {
// set up bitmap
when(mWallpaperBitmap.getColorSpace()).thenReturn(ColorSpace.get(ColorSpace.Named.SRGB));
when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
- when(mWallpaperBitmap.getWidth()).thenReturn(mBitmapWidth);
- when(mWallpaperBitmap.getHeight()).thenReturn(mBitmapHeight);
// set up wallpaper manager
- when(mWallpaperManager.peekBitmapDimensions())
- .thenReturn(new Rect(0, 0, mBitmapWidth, mBitmapHeight));
when(mWallpaperManager.getBitmapAsUser(eq(UserHandle.USER_CURRENT), anyBoolean()))
.thenReturn(mWallpaperBitmap);
when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(mWallpaperManager);
@@ -144,104 +115,62 @@ public class ImageWallpaperTest extends SysuiTestCase {
// set up surface
when(mSurfaceHolder.getSurface()).thenReturn(mSurface);
doNothing().when(mSurface).hwuiDestroy();
-
- // TODO remove code below. Outdated, used in only in old GL tests (that are ignored)
- Resources resources = mock(Resources.class);
- when(resources.getConfiguration()).thenReturn(mock(Configuration.class));
- when(mMockContext.getResources()).thenReturn(resources);
- DisplayInfo displayInfo = new DisplayInfo();
- displayInfo.logicalWidth = DISPLAY_WIDTH;
- displayInfo.logicalHeight = DISPLAY_HEIGHT;
- when(mMockContext.getDisplay()).thenReturn(
- new Display(mock(DisplayManagerGlobal.class), 0, displayInfo, (Resources) null));
- }
-
- private void setBitmapDimensions(int bitmapWidth, int bitmapHeight) {
- mBitmapWidth = bitmapWidth;
- mBitmapHeight = bitmapHeight;
- }
-
- private ImageWallpaper createImageWallpaper() {
- return new ImageWallpaper(mFeatureFlags, mFakeBackgroundExecutor) {
- @Override
- public Engine onCreateEngine() {
- return new GLEngine(mHandler) {
- @Override
- public Context getDisplayContext() {
- return mMockContext;
- }
-
- @Override
- public SurfaceHolder getSurfaceHolder() {
- return mSurfaceHolder;
- }
-
- @Override
- public void setFixedSizeAllowed(boolean allowed) {
- super.setFixedSizeAllowed(allowed);
- assertWithMessage("mFixedSizeAllowed should be true").that(
- allowed).isTrue();
- mEventCountdown.countDown();
- }
- };
- }
- };
}
@Test
- @Ignore
public void testBitmapWallpaper_normal() {
// Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
// Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
- verifySurfaceSize(DISPLAY_WIDTH /* bmpWidth */,
- DISPLAY_WIDTH /* bmpHeight */,
- DISPLAY_WIDTH /* surfaceWidth */,
- DISPLAY_WIDTH /* surfaceHeight */);
+ int bitmapSide = DISPLAY_WIDTH;
+ testSurfaceHelper(
+ bitmapSide /* bitmapWidth */,
+ bitmapSide /* bitmapHeight */,
+ bitmapSide /* expectedSurfaceWidth */,
+ bitmapSide /* expectedSurfaceHeight */);
}
@Test
- @Ignore
public void testBitmapWallpaper_low_resolution() {
// Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
// Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
- verifySurfaceSize(LOW_BMP_WIDTH /* bmpWidth */,
- LOW_BMP_HEIGHT /* bmpHeight */,
- LOW_BMP_WIDTH /* surfaceWidth */,
- LOW_BMP_HEIGHT /* surfaceHeight */);
+ testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */,
+ LOW_BMP_HEIGHT /* bitmapHeight */,
+ LOW_BMP_WIDTH /* expectedSurfaceWidth */,
+ LOW_BMP_HEIGHT /* expectedSurfaceHeight */);
}
@Test
- @Ignore
public void testBitmapWallpaper_too_small() {
- // Will use a image wallpaper with dimensions INVALID_BMP_WIDTH x INVALID_BMP_HEIGHT.
- // Then we expect the surface size will be also MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT.
- verifySurfaceSize(INVALID_BMP_WIDTH /* bmpWidth */,
- INVALID_BMP_HEIGHT /* bmpHeight */,
- ImageWallpaper.GLEngine.MIN_SURFACE_WIDTH /* surfaceWidth */,
- ImageWallpaper.GLEngine.MIN_SURFACE_HEIGHT /* surfaceHeight */);
- }
- private void verifySurfaceSize(int bmpWidth, int bmpHeight,
- int surfaceWidth, int surfaceHeight) {
- ImageWallpaper.GLEngine wallpaperEngine =
- (ImageWallpaper.GLEngine) createImageWallpaper().onCreateEngine();
+ // test that the surface is always at least MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT
+ testMinSurfaceHelper(8, 8);
+ testMinSurfaceHelper(100, 2000);
+ testMinSurfaceHelper(200, 1);
+ }
- ImageWallpaper.GLEngine engineSpy = spy(wallpaperEngine);
+ @Test
+ public void testLoadDrawAndUnloadBitmap() {
+ setBitmapDimensions(LOW_BMP_WIDTH, LOW_BMP_HEIGHT);
- setBitmapDimensions(bmpWidth, bmpHeight);
+ ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
+ spyEngine.onCreate(mSurfaceHolder);
+ spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
+ assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1);
- ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mMockContext);
- doReturn(renderer).when(engineSpy).getRendererInstance();
- engineSpy.onCreate(engineSpy.getSurfaceHolder());
+ int n = 0;
+ while (mFakeBackgroundExecutor.numPending() >= 1) {
+ n++;
+ assertThat(n).isAtMost(10);
+ mFakeBackgroundExecutor.runNextReady();
+ mFakeSystemClock.advanceTime(1000);
+ }
- verify(mSurfaceHolder, times(1)).setFixedSize(surfaceWidth, surfaceHeight);
- assertWithMessage("setFixedSizeAllowed should have been called.").that(
- mEventCountdown.getCount()).isEqualTo(0);
+ verify(spyEngine, times(1)).drawFrameOnCanvas(mWallpaperBitmap);
+ assertThat(spyEngine.isBitmapLoaded()).isFalse();
}
-
- private ImageWallpaper createImageWallpaperCanvas() {
- return new ImageWallpaper(mFeatureFlags, mFakeBackgroundExecutor) {
+ private ImageWallpaper createImageWallpaper() {
+ return new ImageWallpaper(mFakeBackgroundExecutor) {
@Override
public Engine onCreateEngine() {
return new CanvasEngine() {
@@ -267,7 +196,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
}
private ImageWallpaper.CanvasEngine getSpyEngine() {
- ImageWallpaper imageWallpaper = createImageWallpaperCanvas();
+ ImageWallpaper imageWallpaper = createImageWallpaper();
ImageWallpaper.CanvasEngine engine =
(ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
ImageWallpaper.CanvasEngine spyEngine = spy(engine);
@@ -280,48 +209,32 @@ public class ImageWallpaperTest extends SysuiTestCase {
return spyEngine;
}
- @Test
- public void testMinSurface() {
-
- // test that the surface is always at least MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT
- testMinSurfaceHelper(8, 8);
- testMinSurfaceHelper(100, 2000);
- testMinSurfaceHelper(200, 1);
+ private void setBitmapDimensions(int bitmapWidth, int bitmapHeight) {
+ when(mWallpaperManager.peekBitmapDimensions())
+ .thenReturn(new Rect(0, 0, bitmapWidth, bitmapHeight));
+ when(mWallpaperBitmap.getWidth()).thenReturn(bitmapWidth);
+ when(mWallpaperBitmap.getHeight()).thenReturn(bitmapHeight);
}
private void testMinSurfaceHelper(int bitmapWidth, int bitmapHeight) {
+ testSurfaceHelper(bitmapWidth, bitmapHeight,
+ Math.max(ImageWallpaper.CanvasEngine.MIN_SURFACE_WIDTH, bitmapWidth),
+ Math.max(ImageWallpaper.CanvasEngine.MIN_SURFACE_HEIGHT, bitmapHeight));
+ }
+
+ private void testSurfaceHelper(int bitmapWidth, int bitmapHeight,
+ int expectedSurfaceWidth, int expectedSurfaceHeight) {
clearInvocations(mSurfaceHolder);
setBitmapDimensions(bitmapWidth, bitmapHeight);
- ImageWallpaper imageWallpaper = createImageWallpaperCanvas();
+ ImageWallpaper imageWallpaper = createImageWallpaper();
ImageWallpaper.CanvasEngine engine =
(ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
engine.onCreate(mSurfaceHolder);
verify(mSurfaceHolder, times(1)).setFixedSize(
- intThat(greaterThanOrEqualTo(ImageWallpaper.CanvasEngine.MIN_SURFACE_WIDTH)),
- intThat(greaterThanOrEqualTo(ImageWallpaper.CanvasEngine.MIN_SURFACE_HEIGHT)));
- }
-
- @Test
- public void testLoadDrawAndUnloadBitmap() {
- setBitmapDimensions(LOW_BMP_WIDTH, LOW_BMP_HEIGHT);
-
- ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
- spyEngine.onCreate(mSurfaceHolder);
- spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
- assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1);
-
- int n = 0;
- while (mFakeBackgroundExecutor.numPending() >= 1) {
- n++;
- assertThat(n).isAtMost(10);
- mFakeBackgroundExecutor.runNextReady();
- mFakeSystemClock.advanceTime(1000);
- }
-
- verify(spyEngine, times(1)).drawFrameOnCanvas(mWallpaperBitmap);
- assertThat(spyEngine.isBitmapLoaded()).isFalse();
+ intThat(equalTo(expectedSurfaceWidth)),
+ intThat(equalTo(expectedSurfaceHeight)));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/WallpaperLocalColorExtractorTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractorTest.java
index 7e8ffeb7f9e1..fc5f78228f2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/WallpaperLocalColorExtractorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractorTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.wallpapers.canvas;
+package com.android.systemui.wallpapers;
import static com.google.common.truth.Truth.assertThat;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
deleted file mode 100644
index a42badeb228f..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.wallpapers.gl;
-
-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.atMost;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.graphics.PixelFormat;
-import android.testing.AndroidTestingRunner;
-import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.SurfaceHolder;
-import android.view.SurfaceSession;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@Ignore
-public class EglHelperTest extends SysuiTestCase {
-
- @Spy
- private EglHelper mEglHelper;
-
- @Mock
- private SurfaceHolder mSurfaceHolder;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- prepareSurface();
- }
-
- @After
- public void tearDown() {
- mSurfaceHolder.getSurface().destroy();
- mSurfaceHolder = null;
- }
-
- private void prepareSurface() {
- final SurfaceSession session = new SurfaceSession();
- final SurfaceControl control = new SurfaceControl.Builder(session)
- .setName("Test")
- .setBufferSize(100, 100)
- .setFormat(PixelFormat.RGB_888)
- .build();
- final Surface surface = new Surface();
- surface.copyFrom(control);
- when(mSurfaceHolder.getSurface()).thenReturn(surface);
- assertThat(mSurfaceHolder.getSurface()).isNotNull();
- assertThat(mSurfaceHolder.getSurface().isValid()).isTrue();
- }
-
- @Test
- public void testInit_normal() {
- mEglHelper.init(mSurfaceHolder, false /* wideColorGamut */);
- assertThat(mEglHelper.hasEglDisplay()).isTrue();
- assertThat(mEglHelper.hasEglContext()).isTrue();
- assertThat(mEglHelper.hasEglSurface()).isTrue();
- verify(mEglHelper).askCreatingEglWindowSurface(
- any(SurfaceHolder.class), eq(null), anyInt());
- }
-
- @Test
- public void testInit_wide_gamut() {
- // In EglHelper, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
- doReturn(0x3490).when(mEglHelper).getWcgCapability();
- // In EglHelper, KHR_GL_COLOR_SPACE = "EGL_KHR_gl_colorspace";
- doReturn(true).when(mEglHelper).checkExtensionCapability("EGL_KHR_gl_colorspace");
- ArgumentCaptor<int[]> ac = ArgumentCaptor.forClass(int[].class);
- // {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT, EGL_NONE}
- final int[] expectedArgument = new int[] {0x309D, 0x3490, 0x3038};
-
- mEglHelper.init(mSurfaceHolder, true /* wideColorGamut */);
- verify(mEglHelper)
- .askCreatingEglWindowSurface(any(SurfaceHolder.class), ac.capture(), anyInt());
- assertThat(ac.getValue()).isNotNull();
- assertThat(ac.getValue()).isEqualTo(expectedArgument);
- }
-
- @Test
- @Ignore
- public void testFinish_shouldNotCrash() {
- mEglHelper.terminateEglDisplay();
- assertThat(mEglHelper.hasEglDisplay()).isFalse();
- assertThat(mEglHelper.hasEglSurface()).isFalse();
- assertThat(mEglHelper.hasEglContext()).isFalse();
-
- mEglHelper.finish();
- verify(mEglHelper, never()).destroyEglContext();
- verify(mEglHelper, never()).destroyEglSurface();
- verify(mEglHelper, atMost(1)).terminateEglDisplay();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
deleted file mode 100644
index 89b2222df69e..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.wallpapers.gl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-
-import android.app.WallpaperManager;
-import android.app.WallpaperManager.ColorManagementProxy;
-import android.graphics.Bitmap;
-import android.graphics.ColorSpace;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@Ignore
-public class ImageWallpaperRendererTest extends SysuiTestCase {
-
- private WallpaperManager mWpmSpy;
-
- @Before
- public void setUp() throws Exception {
- final WallpaperManager wpm = mContext.getSystemService(WallpaperManager.class);
- mWpmSpy = spy(wpm);
- mContext.addMockSystemService(WallpaperManager.class, mWpmSpy);
- }
-
- @Test
- public void testWcgContent() throws IOException {
- final Bitmap srgbBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
- final Bitmap p3Bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888,
- false /* hasAlpha */, ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
-
- final ColorManagementProxy proxy = new ColorManagementProxy(mContext);
- final ColorManagementProxy cmProxySpy = spy(proxy);
- final Set<ColorSpace> supportedWideGamuts = new HashSet<>();
- supportedWideGamuts.add(ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
-
- try {
- doReturn(true).when(mWpmSpy).shouldEnableWideColorGamut();
- doReturn(cmProxySpy).when(mWpmSpy).getColorManagementProxy();
- doReturn(supportedWideGamuts).when(cmProxySpy).getSupportedColorSpaces();
-
- mWpmSpy.setBitmap(p3Bitmap);
- ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext);
- rendererP3.reportSurfaceSize();
- assertThat(rendererP3.isWcgContent()).isTrue();
-
- mWpmSpy.setBitmap(srgbBitmap);
- ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mContext);
- assertThat(renderer.isWcgContent()).isFalse();
- } finally {
- srgbBitmap.recycle();
- p3Bitmap.recycle();
- }
- }
-
-}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt
index c6aa3952c4b1..021e7dff9120 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt
@@ -67,6 +67,8 @@ class FakeSecurityController(
override fun getDeviceOwnerType(admin: ComponentName?): Int = 0
+ override fun isFinancedDevice(): Boolean = false
+
override fun isNetworkLoggingEnabled(): Boolean = fakeState.isNetworkLoggingEnabled
override fun isVpnEnabled(): Boolean = fakeState.isVpnEnabled
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java
index d5348dc39832..76199e3168da 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java
@@ -84,6 +84,11 @@ public class FakeSecurityController extends BaseLeakChecker<SecurityControllerCa
}
@Override
+ public boolean isFinancedDevice() {
+ return false;
+ }
+
+ @Override
public boolean isNetworkLoggingEnabled() {
return false;
}
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
index 108295b90e58..180b611aa13b 100644
--- a/packages/SystemUI/unfold/Android.bp
+++ b/packages/SystemUI/unfold/Android.bp
@@ -33,6 +33,7 @@ android_library {
"dagger2",
"jsr330",
],
+ kotlincflags: ["-Xjvm-default=enable"],
java_version: "1.8",
min_sdk_version: "current",
plugins: ["dagger2-compiler"],
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
index 7117aafba54a..fee485d97afa 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
@@ -34,8 +34,28 @@ interface UnfoldTransitionProgressProvider : CallbackController<TransitionProgre
fun destroy()
interface TransitionProgressListener {
+ /** Called when transition is started */
+ @JvmDefault
fun onTransitionStarted() {}
- fun onTransitionFinished() {}
+
+ /**
+ * Called whenever transition progress is updated, [progress] is a value of the animation
+ * where 0 is fully folded, 1 is fully unfolded
+ */
+ @JvmDefault
fun onTransitionProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float) {}
+
+ /**
+ * Called when the progress provider determined that the transition is about to finish soon.
+ *
+ * For example, in [PhysicsBasedUnfoldTransitionProgressProvider] this could happen when the
+ * animation is not tied to the hinge angle anymore and it is about to run fixed animation.
+ */
+ @JvmDefault
+ fun onTransitionFinishing() {}
+
+ /** Called when transition is completely finished */
+ @JvmDefault
+ fun onTransitionFinished() {}
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
index 4c85b055aeae..fa59cb4d12be 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
@@ -88,6 +88,7 @@ internal class FixedTimingTransitionProgressProvider(
override fun onAnimationStart(animator: Animator) {
listeners.forEach { it.onTransitionStarted() }
+ listeners.forEach { it.onTransitionFinishing() }
}
override fun onAnimationEnd(animator: Animator) {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 52fb0a79a2bb..ecc029dc1a07 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -125,6 +125,10 @@ class PhysicsBasedUnfoldTransitionProgressProvider(
private fun cancelTransition(endValue: Float, animate: Boolean) {
if (isTransitionRunning && animate) {
+ if (endValue == 1.0f && !isAnimatedCancelRunning) {
+ listeners.forEach { it.onTransitionFinishing() }
+ }
+
isAnimatedCancelRunning = true
springAnimation.animateToFinalPosition(endValue)
} else {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
index 8491f832b740..b7bab3e5ed5a 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
@@ -110,6 +110,12 @@ constructor(source: UnfoldTransitionProgressProvider? = null) :
lastTransitionProgress = progress
}
+ override fun onTransitionFinishing() {
+ if (isReadyToHandleTransition) {
+ listeners.forEach { it.onTransitionFinishing() }
+ }
+ }
+
override fun onTransitionFinished() {
if (isReadyToHandleTransition) {
listeners.forEach { it.onTransitionFinished() }
diff --git a/services/companion/java/com/android/server/companion/MetricUtils.java b/services/companion/java/com/android/server/companion/MetricUtils.java
index 09238d8a1dac..cf867b67cbca 100644
--- a/services/companion/java/com/android/server/companion/MetricUtils.java
+++ b/services/companion/java/com/android/server/companion/MetricUtils.java
@@ -19,6 +19,8 @@ package com.android.server.companion;
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION;
@@ -27,6 +29,8 @@ import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_APP_STREAMING;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_AUTO_PROJECTION;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_COMPUTER;
+import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_GLASSES;
+import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_NEARBY_DEVICE_STREAMING;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_NULL;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_WATCH;
import static com.android.internal.util.FrameworkStatsLog.write;
@@ -59,6 +63,14 @@ final class MetricUtils {
DEVICE_PROFILE_COMPUTER,
CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_COMPUTER
);
+ map.put(
+ DEVICE_PROFILE_GLASSES,
+ CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_GLASSES
+ );
+ map.put(
+ DEVICE_PROFILE_NEARBY_DEVICE_STREAMING,
+ CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_NEARBY_DEVICE_STREAMING
+ );
METRIC_DEVICE_PROFILE = unmodifiableMap(map);
}
diff --git a/services/companion/java/com/android/server/companion/PermissionsUtils.java b/services/companion/java/com/android/server/companion/PermissionsUtils.java
index a41ac03d4513..0ff3fb7a2d58 100644
--- a/services/companion/java/com/android/server/companion/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/PermissionsUtils.java
@@ -23,6 +23,8 @@ import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Binder.getCallingPid;
@@ -65,6 +67,9 @@ public final class PermissionsUtils {
map.put(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION,
Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION);
map.put(DEVICE_PROFILE_COMPUTER, Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER);
+ map.put(DEVICE_PROFILE_GLASSES, Manifest.permission.REQUEST_COMPANION_PROFILE_GLASSES);
+ map.put(DEVICE_PROFILE_NEARBY_DEVICE_STREAMING,
+ Manifest.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING);
DEVICE_PROFILE_TO_PERMISSION = unmodifiableMap(map);
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 48ca0b3abef6..e092f4998c7d 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -78,7 +78,7 @@ public class VirtualDeviceManagerService extends SystemService {
private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler);
private static AtomicInteger sNextUniqueIndex = new AtomicInteger(
- VirtualDeviceManager.DEFAULT_DEVICE_ID + 1);
+ VirtualDeviceManager.DEVICE_ID_DEFAULT + 1);
/**
* Mapping from user IDs to CameraAccessControllers.
@@ -386,14 +386,22 @@ public class VirtualDeviceManagerService extends SystemService {
@Override // BinderCall
@VirtualDeviceParams.DevicePolicy
public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
- return mLocalService.getDevicePolicy(deviceId, policyType);
+ synchronized (mVirtualDeviceManagerLock) {
+ for (int i = 0; i < mVirtualDevices.size(); i++) {
+ final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
+ if (device.getDeviceId() == deviceId) {
+ return device.getDevicePolicy(policyType);
+ }
+ }
+ }
+ return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
}
@Override // Binder call
public int getDeviceIdForDisplayId(int displayId) {
if (displayId == Display.INVALID_DISPLAY || displayId == Display.DEFAULT_DISPLAY) {
- return VirtualDeviceManager.DEFAULT_DEVICE_ID;
+ return VirtualDeviceManager.DEVICE_ID_DEFAULT;
}
synchronized (mVirtualDeviceManagerLock) {
for (int i = 0; i < mVirtualDevices.size(); i++) {
@@ -403,7 +411,7 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
}
- return VirtualDeviceManager.DEFAULT_DEVICE_ID;
+ return VirtualDeviceManager.DEVICE_ID_DEFAULT;
}
@Nullable
@@ -487,20 +495,6 @@ public class VirtualDeviceManagerService extends SystemService {
}
@Override
- @VirtualDeviceParams.DevicePolicy
- public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
- synchronized (mVirtualDeviceManagerLock) {
- for (int i = 0; i < mVirtualDevices.size(); i++) {
- final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
- if (device.getDeviceId() == deviceId) {
- return device.getDevicePolicy(policyType);
- }
- }
- }
- return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
- }
-
- @Override
public void onVirtualDisplayCreated(int displayId) {
final VirtualDisplayListener[] listeners;
synchronized (mVirtualDeviceManagerLock) {
@@ -561,19 +555,6 @@ public class VirtualDeviceManagerService extends SystemService {
}
@Override
- public boolean isAppOwnerOfAnyVirtualDevice(int uid) {
- synchronized (mVirtualDeviceManagerLock) {
- int size = mVirtualDevices.size();
- for (int i = 0; i < size; i++) {
- if (mVirtualDevices.valueAt(i).getOwnerUid() == uid) {
- return true;
- }
- }
- return false;
- }
- }
-
- @Override
public boolean isAppRunningOnAnyVirtualDevice(int uid) {
synchronized (mVirtualDeviceManagerLock) {
int size = mVirtualDevices.size();
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index cbe6091f9d04..17002d5b6e63 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -19,6 +19,8 @@ package com.android.server;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.apex.ApexInfo;
+import android.apex.IApexService;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -39,6 +41,7 @@ import android.content.pm.SigningInfo;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@@ -61,7 +64,6 @@ import com.android.internal.util.FrameworkStatsLog;
import libcore.util.HexEncoding;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.security.PublicKey;
@@ -73,7 +75,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* @hide
@@ -105,7 +106,6 @@ public class BinaryTransparencyService extends SystemService {
@VisibleForTesting
static final String BUNDLE_CONTENT_DIGEST = "content-digest";
- static final String APEX_PRELOAD_LOCATION = "/system/apex/";
static final String APEX_PRELOAD_LOCATION_ERROR = "could-not-be-determined";
// used for indicating any type of error during MBA measurement
@@ -119,7 +119,7 @@ public class BinaryTransparencyService extends SystemService {
// used for indicating newly installed MBAs that are updated (but unused currently)
static final int MBA_STATUS_UPDATED_NEW_INSTALL = 4;
- private static final boolean DEBUG = true; // set this to false upon submission
+ private static final boolean DEBUG = false; // toggle this for local debug
private final Context mContext;
private String mVbmetaDigest;
@@ -320,9 +320,7 @@ public class BinaryTransparencyService extends SystemService {
FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
packageInfo.packageName,
packageInfo.getLongVersionCode(),
- (cDigest != null) ? HexEncoding.encodeToString(
- packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST),
- false) : null,
+ (cDigest != null) ? HexEncoding.encodeToString(cDigest, false) : null,
packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM),
signerDigestHexStrings, // signer_cert_digest
mba_status, // mba_status
@@ -381,9 +379,7 @@ public class BinaryTransparencyService extends SystemService {
FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
packageInfo.packageName,
packageInfo.getLongVersionCode(),
- (cDigest != null) ? HexEncoding.encodeToString(
- packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST),
- false) : null,
+ (cDigest != null) ? HexEncoding.encodeToString(cDigest, false) : null,
packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM),
signerDigestHexStrings,
MBA_STATUS_NEW_INSTALL, // mba_status
@@ -1168,19 +1164,18 @@ public class BinaryTransparencyService extends SystemService {
@NonNull
private String getOriginalApexPreinstalledLocation(String packageName,
- String currentInstalledLocation) {
- // get a listing of all apex files in /system/apex/
- Set<String> originalApexs = Stream.of(new File(APEX_PRELOAD_LOCATION).listFiles())
- .filter(f -> !f.isDirectory())
- .map(File::getName)
- .collect(Collectors.toSet());
-
- for (String originalApex : originalApexs) {
- if (originalApex.startsWith(packageName)) {
- return APEX_PRELOAD_LOCATION + originalApex;
+ String currentInstalledLocation) {
+ try {
+ IApexService apexService = IApexService.Stub.asInterface(
+ Binder.allowBlocking(ServiceManager.waitForService("apexservice")));
+ for (ApexInfo info : apexService.getAllPackages()) {
+ if (packageName.equals(info.moduleName)) {
+ return info.preinstalledModulePath;
+ }
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to get package list from apexservice", e);
}
-
return APEX_PRELOAD_LOCATION_ERROR;
}
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 84c033cbdf0e..572e9c2a5d82 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -337,12 +337,10 @@ public class BootReceiver extends BroadcastReceiver {
return;
}
- // Check if we should rate limit and abort early if needed. Do this for both proto and
- // non-proto tombstones, even though proto tombstones do not support including the counter
- // of events dropped since rate limiting activated yet.
+ // Check if we should rate limit and abort early if needed.
DropboxRateLimiter.RateLimitResult rateLimitResult =
sDropboxRateLimiter.shouldRateLimit(
- proto ? TAG_TOMBSTONE_PROTO : TAG_TOMBSTONE, processName);
+ proto ? TAG_TOMBSTONE_PROTO_WITH_HEADERS : TAG_TOMBSTONE, processName);
if (rateLimitResult.shouldRateLimit()) return;
HashMap<String, Long> timestamps = readTimestamps();
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index b7f8d38171a2..75788f219d58 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -47,6 +47,7 @@ import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.build.UnboundedSdkLevel;
+import com.android.server.pm.permission.PermissionAllowlist;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -304,24 +305,7 @@ public class SystemConfig {
final ArrayMap<String, List<CarrierAssociatedAppEntry>>
mDisabledUntilUsedPreinstalledCarrierAssociatedApps = new ArrayMap<>();
- final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
- final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
-
- final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>();
- final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();
-
- final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>();
- final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();
-
- final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppPermissions = new ArrayMap<>();
- final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppDenyPermissions = new ArrayMap<>();
-
- final ArrayMap<String, ArrayMap<String, ArraySet<String>>> mApexPrivAppPermissions =
- new ArrayMap<>();
- final ArrayMap<String, ArrayMap<String, ArraySet<String>>> mApexPrivAppDenyPermissions =
- new ArrayMap<>();
-
- final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
+ private final PermissionAllowlist mPermissionAllowlist = new PermissionAllowlist();
// Allowed associations between applications. If there are any entries
// for an app, those are the only associations allowed; otherwise, all associations
@@ -459,64 +443,8 @@ public class SystemConfig {
return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
}
- public ArraySet<String> getPrivAppPermissions(String packageName) {
- return mPrivAppPermissions.get(packageName);
- }
-
- public ArraySet<String> getPrivAppDenyPermissions(String packageName) {
- return mPrivAppDenyPermissions.get(packageName);
- }
-
- /** Get privapp permission allowlist for an apk-in-apex. */
- public ArraySet<String> getApexPrivAppPermissions(String apexName, String apkPackageName) {
- return mApexPrivAppPermissions.getOrDefault(apexName, EMPTY_PERMISSIONS)
- .get(apkPackageName);
- }
-
- /** Get privapp permissions denylist for an apk-in-apex. */
- public ArraySet<String> getApexPrivAppDenyPermissions(String apexName, String apkPackageName) {
- return mApexPrivAppDenyPermissions.getOrDefault(apexName, EMPTY_PERMISSIONS)
- .get(apkPackageName);
- }
-
- public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
- return mVendorPrivAppPermissions.get(packageName);
- }
-
- public ArraySet<String> getVendorPrivAppDenyPermissions(String packageName) {
- return mVendorPrivAppDenyPermissions.get(packageName);
- }
-
- public ArraySet<String> getProductPrivAppPermissions(String packageName) {
- return mProductPrivAppPermissions.get(packageName);
- }
-
- public ArraySet<String> getProductPrivAppDenyPermissions(String packageName) {
- return mProductPrivAppDenyPermissions.get(packageName);
- }
-
- /**
- * Read from "permission" tags in /system_ext/etc/permissions/*.xml
- * @return Set of privileged permissions that are explicitly granted.
- */
- public ArraySet<String> getSystemExtPrivAppPermissions(String packageName) {
- return mSystemExtPrivAppPermissions.get(packageName);
- }
-
- /**
- * Read from "deny-permission" tags in /system_ext/etc/permissions/*.xml
- * @return Set of privileged permissions that are explicitly denied.
- */
- public ArraySet<String> getSystemExtPrivAppDenyPermissions(String packageName) {
- return mSystemExtPrivAppDenyPermissions.get(packageName);
- }
-
- public Map<String, Boolean> getOemPermissions(String packageName) {
- final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
- if (oemPermissions != null) {
- return oemPermissions;
- }
- return Collections.emptyMap();
+ public PermissionAllowlist getPermissionAllowlist() {
+ return mPermissionAllowlist;
}
public ArrayMap<String, ArraySet<String>> getAllowedAssociations() {
@@ -1253,20 +1181,20 @@ public class SystemConfig {
Environment.getApexDirectory().toPath() + "/")
&& ApexProperties.updatable().orElse(false);
if (vendor) {
- readPrivAppPermissions(parser, mVendorPrivAppPermissions,
- mVendorPrivAppDenyPermissions);
+ readPrivAppPermissions(parser,
+ mPermissionAllowlist.getVendorPrivilegedAppAllowlist());
} else if (product) {
- readPrivAppPermissions(parser, mProductPrivAppPermissions,
- mProductPrivAppDenyPermissions);
+ readPrivAppPermissions(parser,
+ mPermissionAllowlist.getProductPrivilegedAppAllowlist());
} else if (systemExt) {
- readPrivAppPermissions(parser, mSystemExtPrivAppPermissions,
- mSystemExtPrivAppDenyPermissions);
+ readPrivAppPermissions(parser,
+ mPermissionAllowlist.getSystemExtPrivilegedAppAllowlist());
} else if (apex) {
readApexPrivAppPermissions(parser, permFile,
Environment.getApexDirectory().toPath());
} else {
- readPrivAppPermissions(parser, mPrivAppPermissions,
- mPrivAppDenyPermissions);
+ readPrivAppPermissions(parser,
+ mPermissionAllowlist.getPrivilegedAppAllowlist());
}
} else {
logNotAllowedInPartition(name, permFile, parser);
@@ -1589,50 +1517,10 @@ public class SystemConfig {
}
}
- private void readPrivAppPermissions(XmlPullParser parser,
- ArrayMap<String, ArraySet<String>> grantMap,
- ArrayMap<String, ArraySet<String>> denyMap)
+ private void readPrivAppPermissions(@NonNull XmlPullParser parser,
+ @NonNull ArrayMap<String, ArrayMap<String, Boolean>> allowlist)
throws IOException, XmlPullParserException {
- String packageName = parser.getAttributeValue(null, "package");
- if (TextUtils.isEmpty(packageName)) {
- Slog.w(TAG, "package is required for <privapp-permissions> in "
- + parser.getPositionDescription());
- return;
- }
-
- ArraySet<String> permissions = grantMap.get(packageName);
- if (permissions == null) {
- permissions = new ArraySet<>();
- }
- ArraySet<String> denyPermissions = denyMap.get(packageName);
- int depth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, depth)) {
- String name = parser.getName();
- if ("permission".equals(name)) {
- String permName = parser.getAttributeValue(null, "name");
- if (TextUtils.isEmpty(permName)) {
- Slog.w(TAG, "name is required for <permission> in "
- + parser.getPositionDescription());
- continue;
- }
- permissions.add(permName);
- } else if ("deny-permission".equals(name)) {
- String permName = parser.getAttributeValue(null, "name");
- if (TextUtils.isEmpty(permName)) {
- Slog.w(TAG, "name is required for <deny-permission> in "
- + parser.getPositionDescription());
- continue;
- }
- if (denyPermissions == null) {
- denyPermissions = new ArraySet<>();
- }
- denyPermissions.add(permName);
- }
- }
- grantMap.put(packageName, permissions);
- if (denyPermissions != null) {
- denyMap.put(packageName, denyPermissions);
- }
+ readPermissionAllowlist(parser, allowlist, "privapp-permissions");
}
private void readInstallInUserType(XmlPullParser parser,
@@ -1683,14 +1571,21 @@ public class SystemConfig {
}
void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
+ readPermissionAllowlist(parser, mPermissionAllowlist.getOemAppAllowlist(),
+ "oem-permissions");
+ }
+
+ private static void readPermissionAllowlist(@NonNull XmlPullParser parser,
+ @NonNull ArrayMap<String, ArrayMap<String, Boolean>> allowlist, @NonNull String tagName)
+ throws IOException, XmlPullParserException {
final String packageName = parser.getAttributeValue(null, "package");
if (TextUtils.isEmpty(packageName)) {
- Slog.w(TAG, "package is required for <oem-permissions> in "
+ Slog.w(TAG, "package is required for <" + tagName + "> in "
+ parser.getPositionDescription());
return;
}
- ArrayMap<String, Boolean> permissions = mOemPermissions.get(packageName);
+ ArrayMap<String, Boolean> permissions = allowlist.get(packageName);
if (permissions == null) {
permissions = new ArrayMap<>();
}
@@ -1698,24 +1593,24 @@ public class SystemConfig {
while (XmlUtils.nextElementWithin(parser, depth)) {
final String name = parser.getName();
if ("permission".equals(name)) {
- final String permName = parser.getAttributeValue(null, "name");
- if (TextUtils.isEmpty(permName)) {
+ final String permissionName = parser.getAttributeValue(null, "name");
+ if (TextUtils.isEmpty(permissionName)) {
Slog.w(TAG, "name is required for <permission> in "
+ parser.getPositionDescription());
continue;
}
- permissions.put(permName, Boolean.TRUE);
+ permissions.put(permissionName, Boolean.TRUE);
} else if ("deny-permission".equals(name)) {
- String permName = parser.getAttributeValue(null, "name");
- if (TextUtils.isEmpty(permName)) {
+ String permissionName = parser.getAttributeValue(null, "name");
+ if (TextUtils.isEmpty(permissionName)) {
Slog.w(TAG, "name is required for <deny-permission> in "
+ parser.getPositionDescription());
continue;
}
- permissions.put(permName, Boolean.FALSE);
+ permissions.put(permissionName, Boolean.FALSE);
}
}
- mOemPermissions.put(packageName, permissions);
+ allowlist.put(packageName, permissions);
}
private void readSplitPermission(XmlPullParser parser, File permFile)
@@ -1865,21 +1760,14 @@ public class SystemConfig {
Path apexDirectoryPath) throws IOException, XmlPullParserException {
final String moduleName =
getApexModuleNameFromFilePath(permFile.toPath(), apexDirectoryPath);
- final ArrayMap<String, ArraySet<String>> privAppPermissions;
- if (mApexPrivAppPermissions.containsKey(moduleName)) {
- privAppPermissions = mApexPrivAppPermissions.get(moduleName);
- } else {
- privAppPermissions = new ArrayMap<>();
- mApexPrivAppPermissions.put(moduleName, privAppPermissions);
- }
- final ArrayMap<String, ArraySet<String>> privAppDenyPermissions;
- if (mApexPrivAppDenyPermissions.containsKey(moduleName)) {
- privAppDenyPermissions = mApexPrivAppDenyPermissions.get(moduleName);
- } else {
- privAppDenyPermissions = new ArrayMap<>();
- mApexPrivAppDenyPermissions.put(moduleName, privAppDenyPermissions);
+ final ArrayMap<String, ArrayMap<String, ArrayMap<String, Boolean>>> allowlists =
+ mPermissionAllowlist.getApexPrivilegedAppAllowlists();
+ ArrayMap<String, ArrayMap<String, Boolean>> allowlist = allowlists.get(moduleName);
+ if (allowlist == null) {
+ allowlist = new ArrayMap<>();
+ allowlists.put(moduleName, allowlist);
}
- readPrivAppPermissions(parser, privAppPermissions, privAppDenyPermissions);
+ readPrivAppPermissions(parser, allowlist);
}
private static boolean isSystemProcess() {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 61f7f301a838..f652cb050cbd 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -371,8 +371,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
return new LocationPermissionChecker(context);
}
- /** Gets the transports that need to be marked as restricted by the VCN */
- public Set<Integer> getRestrictedTransports(
+ /** Gets transports that need to be marked as restricted by the VCN from CarrierConfig */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public Set<Integer> getRestrictedTransportsFromCarrierConfig(
ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot) {
if (!Build.IS_ENG && !Build.IS_USERDEBUG) {
return RESTRICTED_TRANSPORTS_DEFAULT;
@@ -398,6 +399,22 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
return restrictedTransports;
}
+
+ /** Gets the transports that need to be marked as restricted by the VCN */
+ public Set<Integer> getRestrictedTransports(
+ ParcelUuid subGrp,
+ TelephonySubscriptionSnapshot lastSnapshot,
+ VcnConfig vcnConfig) {
+ final Set<Integer> restrictedTransports = new ArraySet<>();
+ restrictedTransports.addAll(vcnConfig.getRestrictedUnderlyingNetworkTransports());
+
+ // TODO: b/262269892 Remove the ability to configure restricted transports
+ // via CarrierConfig
+ restrictedTransports.addAll(
+ getRestrictedTransportsFromCarrierConfig(subGrp, lastSnapshot));
+
+ return restrictedTransports;
+ }
}
/** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -719,6 +736,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
if (mVcns.containsKey(subscriptionGroup)) {
final Vcn vcn = mVcns.get(subscriptionGroup);
vcn.updateConfig(config);
+ notifyAllPolicyListenersLocked();
} else {
// TODO(b/193687515): Support multiple VCNs active at the same time
if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) {
@@ -936,7 +954,6 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
/** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
- @GuardedBy("mLock")
@Override
public void addVcnUnderlyingNetworkPolicyListener(
@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
@@ -963,16 +980,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
});
}
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- void addVcnUnderlyingNetworkPolicyListenerForTest(
- @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
- synchronized (mLock) {
- addVcnUnderlyingNetworkPolicyListener(listener);
- }
- }
-
/** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
- @GuardedBy("mLock")
@Override
public void removeVcnUnderlyingNetworkPolicyListener(
@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
@@ -1062,8 +1070,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
isVcnManagedNetwork = true;
}
- final Set<Integer> restrictedTransports =
- mDeps.getRestrictedTransports(subGrp, mLastSnapshot);
+ final Set<Integer> restrictedTransports = mDeps.getRestrictedTransports(
+ subGrp, mLastSnapshot, mConfigs.get(subGrp));
for (int restrictedTransport : restrictedTransports) {
if (ncCopy.hasTransport(restrictedTransport)) {
if (restrictedTransport == TRANSPORT_CELLULAR) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a2755bec0bc0..88492edc9a73 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3558,8 +3558,7 @@ public class AccountManagerService
Bundle.setDefusable(result, true);
mNumResults++;
Intent intent = null;
- if (result != null
- && (intent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class)) != null) {
+ if (result != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
result)) {
@@ -4928,8 +4927,10 @@ public class AccountManagerService
EventLog.writeEvent(0x534e4554, "250588548", authUid, "");
return false;
}
-
Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
+ if (intent == null) {
+ return true;
+ }
// Explicitly set an empty ClipData to ensure that we don't offer to
// promote any Uris contained inside for granting purposes
if (intent.getClipData() == null) {
@@ -4979,8 +4980,12 @@ public class AccountManagerService
Bundle simulateBundle = p.readBundle();
p.recycle();
Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
- return (intent.filterEquals(simulateBundle.getParcelable(AccountManager.KEY_INTENT,
- Intent.class)));
+ Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT,
+ Intent.class);
+ if (intent == null) {
+ return (simulateIntent == null);
+ }
+ return intent.filterEquals(simulateIntent);
}
private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
@@ -5129,8 +5134,7 @@ public class AccountManagerService
}
}
}
- if (result != null
- && (intent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class)) != null) {
+ if (result != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
result)) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 35b3db8a6332..f72321c5d9ac 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2787,8 +2787,8 @@ public final class ActiveServices {
}
}
- private final AppOpsManager.OnOpNotedListener mOpNotedCallback =
- new AppOpsManager.OnOpNotedListener() {
+ private final AppOpsManager.OnOpNotedInternalListener mOpNotedCallback =
+ new AppOpsManager.OnOpNotedInternalListener() {
@Override
public void onOpNoted(int op, int uid, String pkgName,
String attributionTag, int flags, int result) {
@@ -2939,6 +2939,8 @@ public final class ActiveServices {
void unscheduleShortFgsTimeoutLocked(ServiceRecord sr) {
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
+ mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG,
+ sr);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_TIMEOUT_MSG, sr);
}
@@ -2992,10 +2994,19 @@ public final class ActiveServices {
} catch (RemoteException e) {
// TODO(short-service): Anything to do here?
}
- // Schedule the ANR timeout.
- final Message msg = mAm.mHandler.obtainMessage(
- ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
- mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getAnrTime());
+ // Schedule the procstate demotion timeout and ANR timeout.
+ {
+ final Message msg = mAm.mHandler.obtainMessage(
+ ActivityManagerService.SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG, sr);
+ mAm.mHandler.sendMessageAtTime(
+ msg, sr.getShortFgsInfo().getProcStateDemoteTime());
+ }
+
+ {
+ final Message msg = mAm.mHandler.obtainMessage(
+ ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
+ mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getAnrTime());
+ }
}
}
@@ -3013,6 +3024,21 @@ public final class ActiveServices {
}
}
+ void onShortFgsProcstateTimeout(ServiceRecord sr) {
+ synchronized (mAm) {
+ if (!sr.shouldDemoteShortFgsProcState()) {
+ if (DEBUG_SHORT_SERVICE) {
+ Slog.d(TAG_SERVICE, "[STALE] Short FGS procstate demotion: " + sr);
+ }
+ return;
+ }
+
+ Slog.e(TAG_SERVICE, "Short FGS procstate demoted: " + sr);
+
+ mAm.updateOomAdjLocked(sr.app, OomAdjuster.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT);
+ }
+ }
+
void onShortFgsAnrTimeout(ServiceRecord sr) {
final String reason = "A foreground service of FOREGROUND_SERVICE_TYPE_SHORT_SERVICE"
+ " did not stop within a timeout: " + sr.getComponentName();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 031590b65d61..5a27af057ec9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -137,6 +137,8 @@ import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_
import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_SYSTEM;
import static com.android.server.net.NetworkPolicyManagerInternal.updateBlockedReasonsWithProcState;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND;
+import static com.android.server.pm.UserManagerInternal.USER_START_MODE_FOREGROUND;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
@@ -220,6 +222,7 @@ import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -607,6 +610,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* This applies specifically to activities and broadcasts.
*/
@ChangeId
+ @Overridable
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
public static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273;
@@ -1542,7 +1546,8 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int DISPATCH_SENDING_BROADCAST_EVENT = 74;
static final int DISPATCH_BINDING_SERVICE_EVENT = 75;
static final int SERVICE_SHORT_FGS_TIMEOUT_MSG = 76;
- static final int SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG = 77;
+ static final int SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG = 77;
+ static final int SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG = 78;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1880,6 +1885,9 @@ public class ActivityManagerService extends IActivityManager.Stub
case SERVICE_SHORT_FGS_TIMEOUT_MSG: {
mServices.onShortFgsTimeout((ServiceRecord) msg.obj);
} break;
+ case SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG: {
+ mServices.onShortFgsProcstateTimeout((ServiceRecord) msg.obj);
+ } break;
case SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG: {
mServices.onShortFgsAnrTimeout((ServiceRecord) msg.obj);
} break;
@@ -7430,10 +7438,11 @@ public class ActivityManagerService extends IActivityManager.Stub
if (shareDescription != null) {
triggerShellBugreport.putExtra(EXTRA_DESCRIPTION, shareDescription);
}
+ UserHandle callingUser = Binder.getCallingUserHandle();
final long identity = Binder.clearCallingIdentity();
try {
// Send broadcast to shell to trigger bugreport using Bugreport API
- mContext.sendBroadcastAsUser(triggerShellBugreport, UserHandle.SYSTEM);
+ mContext.sendBroadcastAsUser(triggerShellBugreport, callingUser);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -16575,14 +16584,14 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public boolean startUserInBackgroundWithListener(final int userId,
@Nullable IProgressListener unlockListener) {
- return mUserController.startUser(userId, /* foreground */ false, unlockListener);
+ return mUserController.startUser(userId, USER_START_MODE_BACKGROUND, unlockListener);
}
@Override
public boolean startUserInForegroundWithListener(final int userId,
@Nullable IProgressListener unlockListener) {
// Permission check done inside UserController.
- return mUserController.startUser(userId, /* foreground */ true, unlockListener);
+ return mUserController.startUser(userId, USER_START_MODE_FOREGROUND, unlockListener);
}
@Override
@@ -18380,6 +18389,25 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ long delayedDurationMs) {
+ Objects.requireNonNull(targetPackage);
+ Preconditions.checkArgumentNonnegative(delayedDurationMs);
+ Preconditions.checkState(mEnableModernQueue, "Not valid in legacy queue");
+ enforceCallingPermission(permission.DUMP, "forceDelayBroadcastDelivery()");
+
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.forceDelayBroadcastDelivery(targetPackage, delayedDurationMs);
+ }
+ }
+
+ @Override
+ public boolean isModernBroadcastQueueEnabled() {
+ enforceCallingPermission(permission.DUMP, "isModernBroadcastQueueEnabled()");
+ return mEnableModernQueue;
+ }
+
+ @Override
@ReasonCode
public int getBackgroundRestrictionExemptionReason(int uid) {
enforceCallingPermission(android.Manifest.permission.DEVICE_POWER,
@@ -18535,7 +18563,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int restartUserInBackground(final int userId) {
- return mUserController.restartUser(userId, /* foreground */ false);
+ return mUserController.restartUser(userId, USER_START_MODE_BACKGROUND);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 94c15babb1e5..4a6e5a32a205 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1413,6 +1413,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
mPw.println("shortMsg: " + shortMsg);
mPw.println("longMsg: " + longMsg);
mPw.println("timeMillis: " + timeMillis);
+ mPw.println("uptime: " + SystemClock.uptimeMillis());
mPw.println("stack:");
mPw.print(stackTrace);
mPw.println("#");
@@ -1429,6 +1430,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
mPw.println("processName: " + processName);
mPw.println("processPid: " + pid);
mPw.println("annotation: " + annotation);
+ mPw.println("uptime: " + SystemClock.uptimeMillis());
mPw.flush();
int result = waitControllerLocked(pid, STATE_EARLY_ANR);
if (result == RESULT_EARLY_ANR_KILL) return -1;
@@ -1442,6 +1444,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
mPw.println("** ERROR: PROCESS NOT RESPONDING");
mPw.println("processName: " + processName);
mPw.println("processPid: " + pid);
+ mPw.println("uptime: " + SystemClock.uptimeMillis());
mPw.println("processStats:");
mPw.print(processStats);
mPw.println("#");
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index f5d1c106705d..fe5888df238e 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -236,6 +236,15 @@ public class BroadcastConstants {
private static final int DEFAULT_MAX_HISTORY_SUMMARY_SIZE =
ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
+ /**
+ * For {@link BroadcastQueueModernImpl}: Maximum number of broadcast receivers to process in a
+ * single synchronized block. Up to this many messages may be dispatched in a single binder
+ * call. Set this to 1 (or zero) for pre-batch behavior.
+ */
+ public int MAX_BROADCAST_BATCH_SIZE = DEFAULT_MAX_BROADCAST_BATCH_SIZE;
+ private static final String KEY_MAX_BROADCAST_BATCH_SIZE = "bcast_max_batch_size";
+ private static final int DEFAULT_MAX_BROADCAST_BATCH_SIZE = 1;
+
// Settings override tracking for this instance
private String mSettingsKey;
private SettingsObserver mSettingsObserver;
@@ -373,6 +382,8 @@ public class BroadcastConstants {
DEFAULT_MAX_HISTORY_COMPLETE_SIZE);
MAX_HISTORY_SUMMARY_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_SUMMARY_SIZE,
DEFAULT_MAX_HISTORY_SUMMARY_SIZE);
+ MAX_BROADCAST_BATCH_SIZE = getDeviceConfigInt(KEY_MAX_BROADCAST_BATCH_SIZE,
+ DEFAULT_MAX_BROADCAST_BATCH_SIZE);
}
}
@@ -418,6 +429,7 @@ public class BroadcastConstants {
MAX_CONSECUTIVE_URGENT_DISPATCHES).println();
pw.print(KEY_MAX_CONSECUTIVE_NORMAL_DISPATCHES,
MAX_CONSECUTIVE_NORMAL_DISPATCHES).println();
+ pw.print(KEY_MAX_BROADCAST_BATCH_SIZE, MAX_BROADCAST_BATCH_SIZE).println();
pw.decreaseIndent();
pw.println();
}
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 15d2fa334dcf..7013df123dae 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -183,6 +183,11 @@ class BroadcastProcessQueue {
private String mCachedToString;
private String mCachedToShortString;
+ /**
+ * The duration by which any broadcasts to this process need to be delayed
+ */
+ private long mForcedDelayedDurationMs;
+
public BroadcastProcessQueue(@NonNull BroadcastConstants constants,
@NonNull String processName, int uid) {
this.constants = Objects.requireNonNull(constants);
@@ -275,7 +280,7 @@ class BroadcastProcessQueue {
*/
@FunctionalInterface
public interface BroadcastPredicate {
- public boolean test(@NonNull BroadcastRecord r, int index);
+ boolean test(@NonNull BroadcastRecord r, int index);
}
/**
@@ -284,7 +289,7 @@ class BroadcastProcessQueue {
*/
@FunctionalInterface
public interface BroadcastConsumer {
- public void accept(@NonNull BroadcastRecord r, int index);
+ void accept(@NonNull BroadcastRecord r, int index);
}
/**
@@ -418,6 +423,13 @@ class BroadcastProcessQueue {
}
/**
+ * Get package name of the first application loaded into this process.
+ */
+ public String getPackageName() {
+ return app.getApplicationInfo().packageName;
+ }
+
+ /**
* Set the currently active broadcast to the next pending broadcast.
*/
public void makeActiveNextPending() {
@@ -555,6 +567,10 @@ class BroadcastProcessQueue {
return mActive != null;
}
+ void forceDelayBroadcastDelivery(long delayedDurationMs) {
+ mForcedDelayedDurationMs = delayedDurationMs;
+ }
+
/**
* Will thrown an exception if there are no pending broadcasts; relies on
* {@link #isEmpty()} being false.
@@ -729,6 +745,7 @@ class BroadcastProcessQueue {
static final int REASON_BLOCKED = 4;
static final int REASON_INSTRUMENTED = 5;
static final int REASON_PERSISTENT = 6;
+ static final int REASON_FORCE_DELAYED = 7;
static final int REASON_CONTAINS_FOREGROUND = 10;
static final int REASON_CONTAINS_ORDERED = 11;
static final int REASON_CONTAINS_ALARM = 12;
@@ -746,6 +763,7 @@ class BroadcastProcessQueue {
REASON_BLOCKED,
REASON_INSTRUMENTED,
REASON_PERSISTENT,
+ REASON_FORCE_DELAYED,
REASON_CONTAINS_FOREGROUND,
REASON_CONTAINS_ORDERED,
REASON_CONTAINS_ALARM,
@@ -767,6 +785,7 @@ class BroadcastProcessQueue {
case REASON_BLOCKED: return "BLOCKED";
case REASON_INSTRUMENTED: return "INSTRUMENTED";
case REASON_PERSISTENT: return "PERSISTENT";
+ case REASON_FORCE_DELAYED: return "FORCE_DELAYED";
case REASON_CONTAINS_FOREGROUND: return "CONTAINS_FOREGROUND";
case REASON_CONTAINS_ORDERED: return "CONTAINS_ORDERED";
case REASON_CONTAINS_ALARM: return "CONTAINS_ALARM";
@@ -796,6 +815,7 @@ class BroadcastProcessQueue {
*/
private void updateRunnableAt() {
final SomeArgs next = peekNextBroadcast();
+ mRunnableAtInvalidated = false;
if (next != null) {
final BroadcastRecord r = (BroadcastRecord) next.arg1;
final int index = next.argi1;
@@ -809,7 +829,10 @@ class BroadcastProcessQueue {
return;
}
- if (mCountForeground > 0) {
+ if (mForcedDelayedDurationMs > 0) {
+ mRunnableAt = runnableAt + mForcedDelayedDurationMs;
+ mRunnableAtReason = REASON_FORCE_DELAYED;
+ } else if (mCountForeground > 0) {
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
mRunnableAtReason = REASON_CONTAINS_FOREGROUND;
} else if (mCountInteractive > 0) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 153ad1ec1b52..75e93366bce4 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -233,6 +233,16 @@ public abstract class BroadcastQueue {
public abstract void waitForBarrier(@Nullable PrintWriter pw);
/**
+ * Delays delivering broadcasts to the specified package.
+ *
+ * <p> Note that this is only valid for modern queue.
+ */
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ long delayedDurationMs) {
+ // No default implementation.
+ }
+
+ /**
* Brief summary of internal state, useful for debugging purposes.
*/
@GuardedBy("mService")
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index 1a72fef0683e..8946ada1daf9 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -73,6 +73,7 @@ import android.util.Slog;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
@@ -186,6 +187,14 @@ public class BroadcastQueueImpl extends BroadcastQueue {
}
}
+ /**
+ * This single object allows the queue to dispatch receivers using scheduleReceiverList
+ * without constantly allocating new ReceiverInfo objects or ArrayLists. This queue
+ * implementation is known to have a maximum size of one entry.
+ */
+ @VisibleForTesting
+ final BroadcastReceiverBatch mReceiverBatch = new BroadcastReceiverBatch(1);
+
BroadcastQueueImpl(ActivityManagerService service, Handler handler,
String name, BroadcastConstants constants, boolean allowDelayBehindServices,
int schedGroup) {
@@ -388,10 +397,11 @@ public class BroadcastQueueImpl extends BroadcastQueue {
+ ": " + r);
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
- thread.scheduleReceiver(prepareReceiverIntent(r.intent, r.curFilteredExtras),
+ thread.scheduleReceiverList(mReceiverBatch.manifestReceiver(
+ prepareReceiverIntent(r.intent, r.curFilteredExtras),
r.curReceiver, null /* compatInfo (unused but need to keep method signature) */,
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
- app.mState.getReportedProcState());
+ app.mState.getReportedProcState()));
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
@@ -725,9 +735,10 @@ public class BroadcastQueueImpl extends BroadcastQueue {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
- thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+ thread.scheduleReceiverList(mReceiverBatch.registeredReceiver(
+ receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser,
- app.mState.getReportedProcState());
+ app.mState.getReportedProcState()));
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.
synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index eb5c03bec560..a850c8aac21e 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -87,6 +87,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -140,6 +141,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// We configure runnable size only once at boot; it'd be too complex to
// try resizing dynamically at runtime
mRunning = new BroadcastProcessQueue[mConstants.getMaxRunningQueues()];
+
+ // Set up the statistics for batched broadcasts.
+ final int batchSize = mConstants.MAX_BROADCAST_BATCH_SIZE;
+ mReceiverBatch = new BroadcastReceiverBatch(batchSize);
+ Slog.i(TAG, "maximum broadcast batch size " + batchSize);
}
/**
@@ -202,6 +208,15 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
private final BroadcastConstants mBgConstants;
/**
+ * The sole instance of BroadcastReceiverBatch that is used by scheduleReceiverWarmLocked().
+ * The class is not a true singleton but only one instance is needed for the broadcast queue.
+ * Although this is guarded by mService, it should never be accessed by any other function.
+ */
+ @VisibleForTesting
+ @GuardedBy("mService")
+ final BroadcastReceiverBatch mReceiverBatch;
+
+ /**
* Timestamp when last {@link #testAllProcessQueues} failure was observed;
* used for throttling log messages.
*/
@@ -568,7 +583,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (queue != null) {
// If queue was running a broadcast, fail it
if (queue.isActive()) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"onApplicationCleanupLocked");
}
@@ -741,58 +756,62 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
* case where a broadcast is handled by a remote app, and the case where the
* broadcast was finished locally without the remote app being involved.
*/
+ @GuardedBy("mService")
private void scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) {
checkState(queue.isActive(), "isActive");
+ BroadcastReceiverBatch batch = mReceiverBatch;
+ batch.reset();
- final BroadcastRecord r = queue.getActive();
- final int index = queue.getActiveIndex();
-
- if (r.terminalCount == 0) {
- r.dispatchTime = SystemClock.uptimeMillis();
- r.dispatchRealTime = SystemClock.elapsedRealtime();
- r.dispatchClockTime = System.currentTimeMillis();
- }
-
- if (maybeSkipReceiver(queue, r, index)) {
- return;
+ while (collectReceiverList(queue, batch)) {
+ if (batch.isFull()) {
+ break;
+ }
+ if (!shouldContinueScheduling(queue)) {
+ break;
+ }
+ if (queue.isEmpty()) {
+ break;
+ }
+ queue.makeActiveNextPending();
}
- dispatchReceivers(queue, r, index);
+ processReceiverList(queue, batch);
}
/**
* Examine a receiver and possibly skip it. The method returns true if the receiver is
* skipped (and therefore no more work is required).
*/
- private boolean maybeSkipReceiver(BroadcastProcessQueue queue, BroadcastRecord r, int index) {
+ private boolean maybeSkipReceiver(@NonNull BroadcastProcessQueue queue,
+ @NonNull BroadcastReceiverBatch batch, @NonNull BroadcastRecord r, int index) {
final int oldDeliveryState = getDeliveryState(r, index);
final ProcessRecord app = queue.app;
final Object receiver = r.receivers.get(index);
// If someone already finished this broadcast, finish immediately
if (isDeliveryStateTerminal(oldDeliveryState)) {
- enqueueFinishReceiver(queue, oldDeliveryState, "already terminal state");
+ batch.finish(r, index, oldDeliveryState, "already terminal state");
return true;
}
// Consider additional cases where we'd want to finish immediately
if (app.isInFullBackup()) {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "isInFullBackup");
+ batch.finish(r, index, BroadcastRecord.DELIVERY_SKIPPED, "isInFullBackup");
return true;
}
if (mSkipPolicy.shouldSkip(r, receiver)) {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "mSkipPolicy");
+ batch.finish(r, index, BroadcastRecord.DELIVERY_SKIPPED, "mSkipPolicy");
return true;
}
final Intent receiverIntent = r.getReceiverIntent(receiver);
if (receiverIntent == null) {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "getReceiverIntent");
+ batch.finish(r, index, BroadcastRecord.DELIVERY_SKIPPED, "getReceiverIntent");
return true;
}
// Ignore registered receivers from a previous PID
if ((receiver instanceof BroadcastFilter)
&& ((BroadcastFilter) receiver).receiverList.pid != app.getPid()) {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED,
+ batch.finish(r, index, BroadcastRecord.DELIVERY_SKIPPED,
"BroadcastFilter for mismatched PID");
return true;
}
@@ -801,6 +820,133 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
/**
+ * Collect receivers into a list, to be dispatched in a single receiver list call. Return
+ * true if remaining receivers in the queue should be examined, and false if the current list
+ * is complete.
+ */
+ private boolean collectReceiverList(@NonNull BroadcastProcessQueue queue,
+ @NonNull BroadcastReceiverBatch batch) {
+ final ProcessRecord app = queue.app;
+ final BroadcastRecord r = queue.getActive();
+ final int index = queue.getActiveIndex();
+ final Object receiver = r.receivers.get(index);
+ final Intent receiverIntent = r.getReceiverIntent(receiver);
+
+ if (r.terminalCount == 0) {
+ r.dispatchTime = SystemClock.uptimeMillis();
+ r.dispatchRealTime = SystemClock.elapsedRealtime();
+ r.dispatchClockTime = System.currentTimeMillis();
+ }
+ if (maybeSkipReceiver(queue, batch, r, index)) {
+ return true;
+ }
+
+ final IApplicationThread thread = app.getOnewayThread();
+ if (thread == null) {
+ batch.finish(r, index, BroadcastRecord.DELIVERY_FAILURE, "missing IApplicationThread");
+ return true;
+ }
+
+ if (receiver instanceof BroadcastFilter) {
+ batch.schedule(((BroadcastFilter) receiver).receiverList.receiver,
+ receiverIntent, r.resultCode, r.resultData, r.resultExtras,
+ r.ordered, r.initialSticky, r.userId,
+ app.mState.getReportedProcState(), r, index);
+ // TODO: consider making registered receivers of unordered
+ // broadcasts report results to detect ANRs
+ if (!r.ordered) {
+ batch.success(r, index, BroadcastRecord.DELIVERY_DELIVERED, "assuming delivered");
+ return true;
+ }
+ } else {
+ batch.schedule(receiverIntent, ((ResolveInfo) receiver).activityInfo,
+ null, r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
+ app.mState.getReportedProcState(), r, index);
+ }
+
+ return false;
+ }
+
+ /**
+ * Process the information in a BroadcastReceiverBatch. Elements in the finish and success
+ * lists are sent to enqueueFinishReceiver(). Elements in the receivers list are transmitted
+ * to the target in a single binder call.
+ */
+ private void processReceiverList(@NonNull BroadcastProcessQueue queue,
+ @NonNull BroadcastReceiverBatch batch) {
+ // Transmit the receiver list.
+ final ProcessRecord app = queue.app;
+ final IApplicationThread thread = app.getOnewayThread();
+
+ batch.recordBatch(thread instanceof SameProcessApplicationThread);
+
+ // Mark all the receivers that were discarded. None of these have actually been scheduled.
+ for (int i = 0; i < batch.finished().size(); i++) {
+ final var finish = batch.finished().get(i);
+ enqueueFinishReceiver(queue, finish.r, finish.index, finish.deliveryState,
+ finish.reason);
+ }
+ // Prepare for delivery of all receivers that are about to be scheduled.
+ for (int i = 0; i < batch.cookies().size(); i++) {
+ final var cookie = batch.cookies().get(i);
+ prepareToDispatch(queue, cookie.r, cookie.index);
+ }
+
+ // Notify on dispatch. Note that receiver/cookies are recorded only if the thread is
+ // non-null and the list will therefore be sent.
+ for (int i = 0; i < batch.cookies().size(); i++) {
+ // Cookies and receivers are 1:1
+ final var cookie = batch.cookies().get(i);
+ final BroadcastRecord r = cookie.r;
+ final int index = cookie.index;
+ final Object receiver = r.receivers.get(index);
+ if (receiver instanceof BroadcastFilter) {
+ notifyScheduleRegisteredReceiver(queue.app, r, (BroadcastFilter) receiver);
+ } else {
+ notifyScheduleReceiver(queue.app, r, (ResolveInfo) receiver);
+ }
+ }
+
+ // Transmit the enqueued receivers. The thread cannot be null because the lock has been
+ // held since collectReceiverList(), which will not add any receivers if the thread is null.
+ boolean remoteFailed = false;
+ if (batch.receivers().size() > 0) {
+ try {
+ thread.scheduleReceiverList(batch.receivers());
+ } catch (RemoteException e) {
+ // Log the failure of the first receiver in the list. Note that there must be at
+ // least one receiver/cookie to reach this point in the code, which means
+ // cookie[0] is a valid element.
+ final var info = batch.cookies().get(0);
+ final BroadcastRecord r = info.r;
+ final int index = info.index;
+ final Object receiver = r.receivers.get(index);
+ final String msg = "Failed to schedule " + r + " to " + receiver
+ + " via " + app + ": " + e;
+ logw(msg);
+ app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER, true);
+ remoteFailed = true;
+ }
+ }
+
+ if (!remoteFailed) {
+ // If transmission succeed, report all receivers that are assumed to be delivered.
+ for (int i = 0; i < batch.success().size(); i++) {
+ final var finish = batch.success().get(i);
+ enqueueFinishReceiver(queue, finish.r, finish.index, finish.deliveryState,
+ finish.reason);
+ }
+ } else {
+ // If transmission failed, fail all receivers in the list.
+ for (int i = 0; i < batch.cookies().size(); i++) {
+ final var cookie = batch.cookies().get(i);
+ enqueueFinishReceiver(queue, cookie.r, cookie.index,
+ BroadcastRecord.DELIVERY_FAILURE, "remote app");
+ }
+ }
+ }
+
+ /**
* Return true if this receiver should be assumed to have been delivered.
*/
private boolean isAssumedDelivered(BroadcastRecord r, int index) {
@@ -810,7 +956,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
/**
* A receiver is about to be dispatched. Start ANR timers, if necessary.
*/
- private void dispatchReceivers(BroadcastProcessQueue queue, BroadcastRecord r, int index) {
+ private void prepareToDispatch(@NonNull BroadcastProcessQueue queue,
+ @NonNull BroadcastRecord r, int index) {
final ProcessRecord app = queue.app;
final Object receiver = r.receivers.get(index);
@@ -848,42 +995,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
"scheduleReceiverWarmLocked");
-
- final Intent receiverIntent = r.getReceiverIntent(receiver);
- final IApplicationThread thread = app.getOnewayThread();
- if (thread != null) {
- try {
- if (receiver instanceof BroadcastFilter) {
- notifyScheduleRegisteredReceiver(app, r, (BroadcastFilter) receiver);
- thread.scheduleRegisteredReceiver(
- ((BroadcastFilter) receiver).receiverList.receiver, receiverIntent,
- r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky,
- r.userId, app.mState.getReportedProcState());
-
- // TODO: consider making registered receivers of unordered
- // broadcasts report results to detect ANRs
- if (assumeDelivered) {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_DELIVERED,
- "assuming delivered");
- }
- } else {
- notifyScheduleReceiver(app, r, (ResolveInfo) receiver);
- thread.scheduleReceiver(receiverIntent, ((ResolveInfo) receiver).activityInfo,
- null, r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
- app.mState.getReportedProcState());
- }
- } catch (RemoteException e) {
- final String msg = "Failed to schedule " + r + " to " + receiver
- + " via " + app + ": " + e;
- logw(msg);
- app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");
- }
- } else {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
- "missing IApplicationThread");
- }
}
/**
@@ -898,9 +1009,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
app, OOM_ADJ_REASON_FINISH_RECEIVER);
try {
- thread.scheduleRegisteredReceiver(r.resultTo, r.intent,
+ thread.scheduleReceiverList(mReceiverBatch.registeredReceiver(
+ r.resultTo, r.intent,
r.resultCode, r.resultData, r.resultExtras, false, r.initialSticky,
- r.userId, app.mState.getReportedProcState());
+ r.userId, app.mState.getReportedProcState()));
} catch (RemoteException e) {
final String msg = "Failed to schedule result of " + r + " via " + app + ": " + e;
logw(msg);
@@ -929,7 +1041,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
"deliveryTimeoutHardLocked");
}
@@ -962,7 +1074,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
}
- return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app");
+ return finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app");
}
/**
@@ -978,7 +1090,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
return queue.isRunnable() && queue.isProcessWarm() && !shouldRetire;
}
- private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
+ /**
+ * Terminate all active broadcasts on the queue.
+ */
+ private boolean finishReceiverActiveLocked(@NonNull BroadcastProcessQueue queue,
@DeliveryState int deliveryState, @NonNull String reason) {
if (!queue.isActive()) {
logw("Ignoring finish; no active broadcast for " + queue);
@@ -1004,16 +1119,25 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);
+ final boolean early = r != queue.getActive() || index != queue.getActiveIndex();
+
if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
r.anrCount++;
if (app != null && !app.isDebugging()) {
mService.appNotResponding(queue.app, TimeoutRecord.forBroadcastReceiver(r.intent));
}
- } else {
+ } else if (!early) {
mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_HARD, queue);
}
+ if (early) {
+ // This is an early receiver that was transmitted as part of a group. The delivery
+ // state has been updated but don't make any further decisions.
+ traceEnd(cookie);
+ return false;
+ }
+
final boolean res = shouldContinueScheduling(queue);
if (res) {
// We're on a roll; move onto the next broadcast for this process
@@ -1228,12 +1352,16 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
return didSomething;
}
- private void forEachQueue(@NonNull Consumer<BroadcastProcessQueue> consumer) {
- for (int i = 0; i < mProcessQueues.size(); ++i) {
+ private void forEachMatchingQueue(
+ @NonNull Predicate<BroadcastProcessQueue> queuePredicate,
+ @NonNull Consumer<BroadcastProcessQueue> queueConsumer) {
+ for (int i = 0; i < mProcessQueues.size(); i++) {
BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
while (leaf != null) {
- consumer.accept(leaf);
- updateRunnableList(leaf);
+ if (queuePredicate.test(leaf)) {
+ queueConsumer.accept(leaf);
+ updateRunnableList(leaf);
+ }
leaf = leaf.processNameNext;
}
}
@@ -1297,7 +1425,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
final CountDownLatch latch = new CountDownLatch(1);
synchronized (mService) {
mWaitingFor.add(Pair.create(condition, latch));
- forEachQueue(q -> q.setPrioritizeEarliest(true));
+ forEachMatchingQueue(QUEUE_PREDICATE_ANY,
+ (q) -> q.setPrioritizeEarliest(true));
}
enqueueUpdateRunningList();
try {
@@ -1307,13 +1436,24 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
} finally {
synchronized (mService) {
if (mWaitingFor.isEmpty()) {
- forEachQueue(q -> q.setPrioritizeEarliest(false));
+ forEachMatchingQueue(QUEUE_PREDICATE_ANY,
+ (q) -> q.setPrioritizeEarliest(false));
}
}
}
}
@Override
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ long delayedDurationMs) {
+ synchronized (mService) {
+ forEachMatchingQueue(
+ (q) -> targetPackage.equals(q.getPackageName()),
+ (q) -> q.forceDelayBroadcastDelivery(delayedDurationMs));
+ }
+ }
+
+ @Override
public String describeStateLocked() {
return getRunningSize() + " running";
}
@@ -1694,6 +1834,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
ipw.decreaseIndent();
ipw.println();
+ ipw.println("Batch statistics:");
+ ipw.increaseIndent();
+ {
+ final var stats = mReceiverBatch.getStatistics();
+ ipw.println("Finished " + Arrays.toString(stats.finish));
+ ipw.println("DispatchedLocal " + Arrays.toString(stats.local));
+ ipw.println("DispatchedRemote " + Arrays.toString(stats.remote));
+ }
+ ipw.decreaseIndent();
+ ipw.println();
+
if (dumpConstants) {
mConstants.dump(ipw);
}
diff --git a/services/core/java/com/android/server/am/BroadcastReceiverBatch.java b/services/core/java/com/android/server/am/BroadcastReceiverBatch.java
new file mode 100644
index 000000000000..a8264582b8b3
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastReceiverBatch.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ReceiverInfo;
+import android.content.Intent;
+import android.content.IIntentReceiver;
+import android.content.pm.ActivityInfo;
+import android.content.res.CompatibilityInfo;
+import android.os.Bundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A batch of receiver instructions. This includes a list of finish requests and a list of
+ * receivers. The instructions are for a single queue. It is constructed and consumed in a single
+ * call to {@link BroadcastQueueModernImpl#scheduleReceiverWarmLocked}. The list size is bounded by
+ * {@link BroadcastConstants#MAX_BROADCAST_BATCH_SIZE}. Because this class is ephemeral and its use
+ * is bounded, it is pre-allocated to avoid allocating new objects every time it is used.
+ *
+ * The {@link #single} methods support the use of this class in {@link BroadcastQueueImpl}. These
+ * methods simplify the use of {@link IApplicationThread#scheduleReceiverList} as a replacement
+ * for scheduleReceiver and scheduleRegisteredReceiver.
+ *
+ * This class is designed to be allocated once and constantly reused (call {@link #reset} between
+ * uses). Objects needed by the instance are kept in a pool - all object allocation occurs when
+ * the instance is created, and no allocation occurs thereafter. However, if the variable
+ * mDeepReceiverCopy is set true (it is false by default) then the method {@link #receivers} always
+ * returns newly allocated objects. This is required for mock testing.
+ *
+ * This class is not thread-safe. Instances must be protected by the caller.
+ * @hide
+ */
+final class BroadcastReceiverBatch {
+
+ /**
+ * If this is true then receivers() returns a deep copy of the ReceiveInfo array. If this is
+ * false, receivers() returns a reference to the array. A deep copy is needed only for the
+ * broadcast queue mocking tests.
+ */
+ @VisibleForTesting
+ boolean mDeepReceiverCopy = false;
+
+ /**
+ * A private pool implementation this class.
+ */
+ private static class Pool<T> {
+ final int size;
+ final ArrayList<T> pool;
+ int next;
+ Pool(int n, @NonNull Class<T> c) {
+ size = n;
+ pool = new ArrayList<>(size);
+ try {
+ for (int i = 0; i < size; i++) {
+ pool.add(c.getDeclaredConstructor().newInstance());
+ }
+ } catch (Exception e) {
+ // This class is only used locally. Turn any exceptions into something fatal.
+ throw new RuntimeException(e);
+ }
+ }
+ T next() {
+ return pool.get(next++);
+ }
+ void reset() {
+ next = 0;
+ }
+ }
+
+ /**
+ * The information needed to finish off a receiver. This is valid only in the context of
+ * a queue.
+ */
+ static class FinishInfo {
+ BroadcastRecord r = null;
+ int index = 0;
+ int deliveryState = 0;
+ String reason = null;
+ FinishInfo set(@Nullable BroadcastRecord r, int index,
+ int deliveryState, @Nullable String reason) {
+ this.r = r;
+ this.index = index;
+ this.deliveryState = deliveryState;
+ this.reason = reason;
+ return this;
+ }
+ }
+
+ /**
+ * The information needed to recreate a receiver info. The broadcast record can be null if the
+ * caller does not expect to need it later.
+ */
+ static class ReceiverCookie {
+ BroadcastRecord r = null;
+ int index = 0;
+ ReceiverCookie set(@Nullable BroadcastRecord r, int index) {
+ this.r = r;
+ this.index = index;
+ return this;
+ }
+ }
+
+ // The object pools.
+ final int mSize;
+ private final Pool<ReceiverInfo> receiverPool;
+ private final Pool<FinishInfo> finishPool;
+ private final Pool<ReceiverCookie> cookiePool;
+
+ // The accumulated data. The receivers should be an ArrayList to be directly compatible
+ // with scheduleReceiverList(). The receivers array is not final because a new array must
+ // be created for every new call to scheduleReceiverList().
+ private final ArrayList<ReceiverInfo> mReceivers;
+ private final ArrayList<ReceiverCookie> mCookies;
+ private final ArrayList<FinishInfo> mFinished;
+ // The list of finish records to complete if the binder succeeds or fails.
+ private final ArrayList<FinishInfo> mSuccess;
+
+ BroadcastReceiverBatch(int size) {
+ mSize = size;
+ mReceivers = new ArrayList<>(mSize);
+ mCookies = new ArrayList<>(mSize);
+ mFinished = new ArrayList<>(mSize);
+ mSuccess = new ArrayList<>(mSize);
+
+ receiverPool = new Pool<>(mSize, ReceiverInfo.class);
+ finishPool = new Pool<>(mSize, FinishInfo.class);
+ cookiePool = new Pool<>(mSize, ReceiverCookie.class);
+ mStats = new Statistics(mSize);
+ reset();
+ }
+
+ void reset() {
+ mReceivers.clear();
+ mCookies.clear();
+ mFinished.clear();
+ mSuccess.clear();
+
+ receiverPool.reset();
+ finishPool.reset();
+ cookiePool.reset();
+ }
+
+ void finish(@Nullable BroadcastRecord r, int index,
+ int deliveryState, @Nullable String reason) {
+ mFinished.add(finishPool.next().set(r, index, deliveryState, reason));
+ }
+ void success(@Nullable BroadcastRecord r, int index,
+ int deliveryState, @Nullable String reason) {
+ mSuccess.add(finishPool.next().set(r, index, deliveryState, reason));
+ }
+ // Add a ReceiverInfo for a registered receiver.
+ void schedule(@Nullable IIntentReceiver receiver, Intent intent,
+ int resultCode, @Nullable String data, @Nullable Bundle extras, boolean ordered,
+ boolean sticky, int sendingUser, int processState,
+ @Nullable BroadcastRecord r, int index) {
+ ReceiverInfo ri = new ReceiverInfo();
+ ri.intent = intent;
+ ri.data = data;
+ ri.extras = extras;
+ ri.sendingUser = sendingUser;
+ ri.processState = processState;
+ ri.resultCode = resultCode;
+ ri.registered = true;
+ ri.receiver = receiver;
+ ri.ordered = ordered;
+ ri.sticky = sticky;
+ mReceivers.add(ri);
+ mCookies.add(cookiePool.next().set(r, index));
+ }
+ // Add a ReceiverInfo for a manifest receiver.
+ void schedule(@Nullable Intent intent, @Nullable ActivityInfo activityInfo,
+ @Nullable CompatibilityInfo compatInfo, int resultCode, @Nullable String data,
+ @Nullable Bundle extras, boolean sync, int sendingUser, int processState,
+ @Nullable BroadcastRecord r, int index) {
+ ReceiverInfo ri = new ReceiverInfo();
+ ri.intent = intent;
+ ri.data = data;
+ ri.extras = extras;
+ ri.sendingUser = sendingUser;
+ ri.processState = processState;
+ ri.resultCode = resultCode;
+ ri.registered = false;
+ ri.activityInfo = activityInfo;
+ ri.compatInfo = compatInfo;
+ ri.sync = sync;
+ mReceivers.add(ri);
+ mCookies.add(cookiePool.next().set(r, index));
+ }
+
+ /**
+ * Two convenience functions for dispatching a single receiver. The functions start with a
+ * reset. Then they create the ReceiverInfo array and return it. Statistics are not
+ * collected.
+ */
+ ArrayList<ReceiverInfo> registeredReceiver(@Nullable IIntentReceiver receiver,
+ @Nullable Intent intent, int resultCode, @Nullable String data,
+ @Nullable Bundle extras, boolean ordered, boolean sticky,
+ int sendingUser, int processState) {
+ reset();
+ schedule(receiver, intent, resultCode, data, extras, ordered, sticky,
+ sendingUser, processState, null, 0);
+ return receivers();
+ }
+
+ ArrayList<ReceiverInfo> manifestReceiver(@Nullable Intent intent,
+ @Nullable ActivityInfo activityInfo, @Nullable CompatibilityInfo compatInfo,
+ int resultCode, @Nullable String data, @Nullable Bundle extras, boolean sync,
+ int sendingUser, int processState) {
+ reset();
+ schedule(intent, activityInfo, compatInfo, resultCode, data, extras, sync,
+ sendingUser, processState, null, 0);
+ return receivers();
+ }
+
+ // Return true if the batch is full. Adding any more entries will throw an exception.
+ boolean isFull() {
+ return (mFinished.size() + mReceivers.size()) >= mSize;
+ }
+ int finishCount() {
+ return mFinished.size() + mSuccess.size();
+ }
+ int receiverCount() {
+ return mReceivers.size();
+ }
+
+ /**
+ * Create a deep copy of the receiver list. This is only for testing which is confused when
+ * objects are reused.
+ */
+ private ArrayList<ReceiverInfo> copyReceiverInfo() {
+ ArrayList<ReceiverInfo> copy = new ArrayList<>();
+ for (int i = 0; i < mReceivers.size(); i++) {
+ final ReceiverInfo r = mReceivers.get(i);
+ final ReceiverInfo n = new ReceiverInfo();
+ n.intent = r.intent;
+ n.data = r.data;
+ n.extras = r.extras;
+ n.sendingUser = r.sendingUser;
+ n.processState = r.processState;
+ n.resultCode = r.resultCode;
+ n.registered = r.registered;
+ n.receiver = r.receiver;
+ n.ordered = r.ordered;
+ n.sticky = r.sticky;
+ n.activityInfo = r.activityInfo;
+ n.compatInfo = r.compatInfo;
+ n.sync = r.sync;
+ copy.add(n);
+ }
+ return copy;
+ }
+
+ /**
+ * Accessors for the accumulated instructions. The important accessor is receivers(), since
+ * it can be modified to return a deep copy of the mReceivers array.
+ */
+ @NonNull
+ ArrayList<ReceiverInfo> receivers() {
+ if (!mDeepReceiverCopy) {
+ return mReceivers;
+ } else {
+ return copyReceiverInfo();
+ }
+ }
+ @NonNull
+ ArrayList<ReceiverCookie> cookies() {
+ return mCookies;
+ }
+ @NonNull
+ ArrayList<FinishInfo> finished() {
+ return mFinished;
+ }
+ @NonNull
+ ArrayList<FinishInfo> success() {
+ return mSuccess;
+ }
+
+ /**
+ * A simple POD for statistics. The parameter is the size of the BroadcastReceiverBatch.
+ */
+ static class Statistics {
+ final int[] finish;
+ final int[] local;
+ final int[] remote;
+ Statistics(int size) {
+ finish = new int[size+1];
+ local = new int[size+1];
+ remote = new int[size+1];
+ }
+ }
+
+ private final Statistics mStats;
+
+ /**
+ * A unique counter that identifies individual transmission groups. This is only used for
+ * debugging. It is used to determine which receivers were sent in the same batch, and in
+ * which order. This is static to distinguish between batches across all queues in the
+ * system.
+ */
+ private static final AtomicInteger sTransmitGroup = new AtomicInteger(0);
+
+ /**
+ * Record statistics for this batch of instructions. This updates the local statistics and it
+ * updates the transmitGroup and transmitOrder fields of the BroadcastRecords being
+ * dispatched.
+ */
+ void recordBatch(boolean local) {
+ final int group = sTransmitGroup.addAndGet(1);
+ for (int i = 0; i < cookies().size(); i++) {
+ final var cookie = cookies().get(i);
+ cookie.r.transmitGroup[cookie.index] = group;
+ cookie.r.transmitOrder[cookie.index] = i;
+ }
+ mStats.finish[finishCount()]++;
+ if (local) {
+ mStats.local[receiverCount()]++;
+ } else {
+ mStats.remote[receiverCount()]++;
+ }
+ }
+
+ @NonNull
+ Statistics getStatistics() {
+ return mStats;
+ }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 100b2db691de..24cf3d280063 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -113,6 +113,8 @@ final class BroadcastRecord extends Binder {
@UptimeMillisLong long finishTime; // when broadcast finished
final @UptimeMillisLong long[] scheduledTime; // when each receiver was scheduled
final @UptimeMillisLong long[] terminalTime; // when each receiver was terminal
+ final int[] transmitGroup; // the batch group for each receiver
+ final int[] transmitOrder; // the position of the receiver in the group
final boolean timeoutExempt; // true if this broadcast is not subject to receiver timeouts
int resultCode; // current result code value.
@Nullable String resultData; // current result data value.
@@ -380,6 +382,8 @@ final class BroadcastRecord extends Binder {
blockedUntilTerminalCount = calculateBlockedUntilTerminalCount(receivers, _serialized);
scheduledTime = new long[delivery.length];
terminalTime = new long[delivery.length];
+ transmitGroup = new int[delivery.length];
+ transmitOrder = new int[delivery.length];
resultToApp = _resultToApp;
resultTo = _resultTo;
resultCode = _resultCode;
@@ -433,6 +437,8 @@ final class BroadcastRecord extends Binder {
blockedUntilTerminalCount = from.blockedUntilTerminalCount;
scheduledTime = from.scheduledTime;
terminalTime = from.terminalTime;
+ transmitGroup = from.transmitGroup;
+ transmitOrder = from.transmitOrder;
resultToApp = from.resultToApp;
resultTo = from.resultTo;
enqueueTime = from.enqueueTime;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 66a8babe224e..dbd58eb68253 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -163,6 +163,7 @@ public class OomAdjuster {
static final int OOM_ADJ_REASON_ALLOWLIST = 10;
static final int OOM_ADJ_REASON_PROCESS_BEGIN = 11;
static final int OOM_ADJ_REASON_PROCESS_END = 12;
+ static final int OOM_ADJ_REASON_SHORT_FGS_TIMEOUT = 13;
@IntDef(prefix = {"OOM_ADJ_REASON_"},
value = {OOM_ADJ_REASON_NONE, OOM_ADJ_REASON_ACTIVITY, OOM_ADJ_REASON_FINISH_RECEIVER,
@@ -170,7 +171,8 @@ public class OomAdjuster {
OOM_ADJ_REASON_UNBIND_SERVICE, OOM_ADJ_REASON_START_SERVICE,
OOM_ADJ_REASON_GET_PROVIDER, OOM_ADJ_REASON_REMOVE_PROVIDER,
OOM_ADJ_REASON_UI_VISIBILITY, OOM_ADJ_REASON_ALLOWLIST,
- OOM_ADJ_REASON_PROCESS_BEGIN, OOM_ADJ_REASON_PROCESS_END})
+ OOM_ADJ_REASON_PROCESS_BEGIN, OOM_ADJ_REASON_PROCESS_END,
+ OOM_ADJ_REASON_SHORT_FGS_TIMEOUT})
@Retention(RetentionPolicy.SOURCE)
public @interface OomAdjReason {}
@@ -202,6 +204,7 @@ public class OomAdjuster {
return AppProtoEnums.OOM_ADJ_REASON_PROCESS_BEGIN;
case OOM_ADJ_REASON_PROCESS_END:
return AppProtoEnums.OOM_ADJ_REASON_PROCESS_END;
+ case OOM_ADJ_REASON_SHORT_FGS_TIMEOUT: // TODO(short-service) add value to AppProtoEnums
default:
return AppProtoEnums.OOM_ADJ_REASON_UNKNOWN_TO_PROTO;
}
@@ -236,6 +239,8 @@ public class OomAdjuster {
return OOM_ADJ_REASON_METHOD + "_processBegin";
case OOM_ADJ_REASON_PROCESS_END:
return OOM_ADJ_REASON_METHOD + "_processEnd";
+ case OOM_ADJ_REASON_SHORT_FGS_TIMEOUT:
+ return OOM_ADJ_REASON_METHOD + "_shortFgs";
default:
return "_unknown";
}
@@ -704,7 +709,9 @@ public class OomAdjuster {
ConnectionRecord cr = psr.getConnectionAt(i);
ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
? cr.binding.service.isolationHostProc : cr.binding.service.app;
- if (service == null || service == pr) {
+ if (service == null || service == pr
+ || ((service.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ)
+ && (service.mState.getMaxAdj() < FOREGROUND_APP_ADJ))) {
continue;
}
containsCycle |= service.mState.isReachable();
@@ -724,7 +731,9 @@ public class OomAdjuster {
for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) {
ContentProviderConnection cpc = ppr.getProviderConnectionAt(i);
ProcessRecord provider = cpc.provider.proc;
- if (provider == null || provider == pr) {
+ if (provider == null || provider == pr
+ || ((provider.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ)
+ && (provider.mState.getMaxAdj() < FOREGROUND_APP_ADJ))) {
continue;
}
containsCycle |= provider.mState.isReachable();
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 4706c26889de..33d7f9d04185 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1016,6 +1016,11 @@ class ProcessRecord implements WindowProcessListener {
return mWindowProcessController.hasRecentTasks();
}
+ @GuardedBy("mService")
+ public ApplicationInfo getApplicationInfo() {
+ return info;
+ }
+
@GuardedBy({"mService", "mProcLock"})
boolean onCleanupApplicationRecordLSP(ProcessStatsService processStats, boolean allowRestart,
boolean unlinkDeath) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8ac10b85f634..05726f4c39eb 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1420,6 +1420,20 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
/**
+ * @return true if it's a short FGS's procstate should be demoted.
+ */
+ public boolean shouldDemoteShortFgsProcState() {
+ if (!isAppAlive()) {
+ return false;
+ }
+ if (!this.startRequested || !isShortFgs() || mShortFgsInfo == null
+ || !mShortFgsInfo.isCurrent()) {
+ return false;
+ }
+ return mShortFgsInfo.getProcStateDemoteTime() <= SystemClock.uptimeMillis();
+ }
+
+ /**
* @return true if it's a short FGS that's still up and running, and should be declared
* an ANR.
*/
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 2a693634087b..4e1d1ca0ac66 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -97,6 +97,15 @@
{ "include-filter": "com.android.server.am.BroadcastQueueTest" },
{ "include-filter": "com.android.server.am.BroadcastQueueModernImplTest" }
]
+ },
+ {
+ "file_patterns": ["Broadcast"],
+ "name": "CtsBroadcastTestCases",
+ "options": [
+ { "exclude-annotation": "androidx.test.filters.LargeTest" },
+ { "exclude-annotation": "androidx.test.filters.FlakyTest" },
+ { "exclude-annotation": "org.junit.Ignore" }
+ ]
}
],
"presubmit-large": [
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index aefa2f5bf66e..280256fb49d7 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -46,6 +46,11 @@ import static com.android.server.am.UserState.STATE_BOOTING;
import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKED;
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKING;
+import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
+import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND_VISIBLE;
+import static com.android.server.pm.UserManagerInternal.USER_START_MODE_FOREGROUND;
+import static com.android.server.pm.UserManagerInternal.userAssignmentResultToString;
+import static com.android.server.pm.UserManagerInternal.userStartModeToString;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -119,6 +124,7 @@ import com.android.server.SystemServiceManager;
import com.android.server.am.UserState.KeyEvictedCallback;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
+import com.android.server.pm.UserManagerInternal.UserStartMode;
import com.android.server.pm.UserManagerService;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -903,14 +909,14 @@ class UserController implements Handler.Callback {
});
}
- int restartUser(final int userId, final boolean foreground) {
+ int restartUser(final int userId, @UserStartMode int userStartMode) {
return stopUser(userId, /* force= */ true, /* allowDelayedLocking= */ false,
/* stopUserCallback= */ null, new KeyEvictedCallback() {
@Override
public void keyEvicted(@UserIdInt int userId) {
// Post to the same handler that this callback is called from to ensure
// the user cleanup is complete before restarting.
- mHandler.post(() -> UserController.this.startUser(userId, foreground));
+ mHandler.post(() -> UserController.this.startUser(userId, userStartMode));
}
});
}
@@ -1267,7 +1273,7 @@ class UserController implements Handler.Callback {
if (userStart.userId == userId) {
Slogf.i(TAG, "resumePendingUserStart for" + userStart);
mHandler.post(() -> startUser(userStart.userId,
- userStart.isForeground, userStart.unlockListener));
+ userStart.userStartMode, userStart.unlockListener));
handledUserStarts.add(userStart);
}
@@ -1450,7 +1456,7 @@ class UserController implements Handler.Callback {
for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) {
// NOTE: this method is setting the profiles of the current user - which is always
// assigned to the default display
- startUser(profilesToStart.get(i).id, /* foreground= */ false);
+ startUser(profilesToStart.get(i).id, USER_START_MODE_BACKGROUND_VISIBLE);
}
if (i < profilesToStartSize) {
Slogf.w(TAG, "More profiles than MAX_RUNNING_USERS");
@@ -1492,18 +1498,20 @@ class UserController implements Handler.Callback {
return false;
}
- return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, /* foreground= */ false,
- /* unlockListener= */ null);
+ return startUserNoChecks(userId, Display.DEFAULT_DISPLAY,
+ USER_START_MODE_BACKGROUND_VISIBLE, /* unlockListener= */ null);
}
@VisibleForTesting
- boolean startUser(final @UserIdInt int userId, final boolean foreground) {
- return startUser(userId, foreground, null);
+ boolean startUser(@UserIdInt int userId, @UserStartMode int userStartMode) {
+ return startUser(userId, userStartMode, /* unlockListener= */ null);
}
/**
* Start user, if its not already running.
- * <p>The user will be brought to the foreground, if {@code foreground} parameter is set.
+ *
+ * <p>The user will be brought to the foreground, if {@code userStartMode} parameter is
+ * set to {@link UserManagerInternal#USER_START_MODE_FOREGROUND}
* When starting the user, multiple intents will be broadcast in the following order:</p>
* <ul>
* <li>{@link Intent#ACTION_USER_STARTED} - sent to registered receivers of the new user
@@ -1529,17 +1537,15 @@ class UserController implements Handler.Callback {
* </ul>
*
* @param userId ID of the user to start
- * @param foreground true if user should be brought to the foreground
+ * @param userStartMode user starting mode
* @param unlockListener Listener to be informed when the user has started and unlocked.
* @return true if the user has been successfully started
*/
- boolean startUser(
- final @UserIdInt int userId,
- final boolean foreground,
+ boolean startUser(@UserIdInt int userId, @UserStartMode int userStartMode,
@Nullable IProgressListener unlockListener) {
checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUser");
- return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, foreground, unlockListener);
+ return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, userStartMode, unlockListener);
}
/**
@@ -1572,7 +1578,7 @@ class UserController implements Handler.Callback {
"Cannot use DEFAULT_DISPLAY");
try {
- return startUserNoChecks(userId, displayId, /* foreground= */ false,
+ return startUserNoChecks(userId, displayId, USER_START_MODE_BACKGROUND_VISIBLE,
/* unlockListener= */ null);
} catch (RuntimeException e) {
Slogf.e(TAG, "startUserOnSecondaryDisplay(%d, %d) failed: %s", userId, displayId, e);
@@ -1580,26 +1586,29 @@ class UserController implements Handler.Callback {
}
}
- private boolean startUserNoChecks(@UserIdInt int userId, int displayId, boolean foreground,
- @Nullable IProgressListener unlockListener) {
+ private boolean startUserNoChecks(@UserIdInt int userId, int displayId,
+ @UserStartMode int userStartMode, @Nullable IProgressListener unlockListener) {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("UserController.startUser-" + userId
+ (displayId == Display.DEFAULT_DISPLAY ? "" : "-display-" + displayId)
- + "-" + (foreground ? "fg" : "bg"));
+ + "-" + (userStartMode == USER_START_MODE_FOREGROUND ? "fg" : "bg")
+ + "-start-mode-" + userStartMode);
try {
- return startUserInternal(userId, displayId, foreground, unlockListener, t);
+ return startUserInternal(userId, displayId, userStartMode, unlockListener, t);
} finally {
t.traceEnd();
}
}
- private boolean startUserInternal(@UserIdInt int userId, int displayId, boolean foreground,
- @Nullable IProgressListener unlockListener, @NonNull TimingsTraceAndSlog t) {
+ private boolean startUserInternal(@UserIdInt int userId, int displayId,
+ @UserStartMode int userStartMode, @Nullable IProgressListener unlockListener,
+ TimingsTraceAndSlog t) {
if (DEBUG_MU) {
- Slogf.i(TAG, "Starting user %d on display %d%s", userId, displayId,
- foreground ? " in foreground" : "");
+ Slogf.i(TAG, "Starting user %d on display %d with mode %s", userId, displayId,
+ userStartModeToString(userStartMode));
}
+ boolean foreground = userStartMode == USER_START_MODE_FOREGROUND;
boolean onSecondaryDisplay = displayId != Display.DEFAULT_DISPLAY;
if (onSecondaryDisplay) {
@@ -1664,13 +1673,13 @@ class UserController implements Handler.Callback {
t.traceBegin("assignUserToDisplayOnStart");
int result = mInjector.getUserManagerInternal().assignUserToDisplayOnStart(userId,
- userInfo.profileGroupId, foreground, displayId);
+ userInfo.profileGroupId, userStartMode, displayId);
t.traceEnd();
- if (result == UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE) {
+ if (result == USER_ASSIGNMENT_RESULT_FAILURE) {
Slogf.e(TAG, "%s user(%d) / display (%d) assignment failed: %s",
- (foreground ? "fg" : "bg"), userId, displayId,
- UserManagerInternal.userAssignmentResultToString(result));
+ userStartModeToString(userStartMode), userId, displayId,
+ userAssignmentResultToString(result));
return false;
}
@@ -1700,8 +1709,8 @@ class UserController implements Handler.Callback {
} else if (uss.state == UserState.STATE_SHUTDOWN) {
Slogf.i(TAG, "User #" + userId
+ " is shutting down - will start after full shutdown");
- mPendingUserStarts.add(new PendingUserStart(userId,
- foreground, unlockListener));
+ mPendingUserStarts.add(new PendingUserStart(userId, userStartMode,
+ unlockListener));
t.traceEnd(); // updateStartedUserArrayStarting
return true;
}
@@ -1862,8 +1871,8 @@ class UserController implements Handler.Callback {
/**
* Start user, if its not already running, and bring it to foreground.
*/
- void startUserInForeground(final int targetUserId) {
- boolean success = startUser(targetUserId, /* foreground */ true);
+ void startUserInForeground(@UserIdInt int targetUserId) {
+ boolean success = startUser(targetUserId, USER_START_MODE_FOREGROUND);
if (!success) {
mInjector.getWindowManager().setSwitchingUser(false);
}
@@ -3433,13 +3442,13 @@ class UserController implements Handler.Callback {
*/
private static class PendingUserStart {
public final @UserIdInt int userId;
- public final boolean isForeground;
+ public final @UserStartMode int userStartMode;
public final IProgressListener unlockListener;
- PendingUserStart(int userId, boolean foreground,
+ PendingUserStart(int userId, @UserStartMode int userStartMode,
IProgressListener unlockListener) {
this.userId = userId;
- this.isForeground = foreground;
+ this.userStartMode = userStartMode;
this.unlockListener = unlockListener;
}
@@ -3447,7 +3456,7 @@ class UserController implements Handler.Callback {
public String toString() {
return "PendingUserStart{"
+ "userId=" + userId
- + ", isForeground=" + isForeground
+ + ", userStartMode=" + userStartModeToString(userStartMode)
+ ", unlockListener=" + unlockListener
+ '}';
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 2fe06094bd88..418027fb37f6 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1998,4 +1998,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
return mDeviceInventory.getDeviceSensorUuid(device);
}
}
+
+ void dispatchPreferredMixerAttributesChangedCausedByDeviceRemoved(AudioDeviceInfo info) {
+ // Currently, only media usage will be allowed to set preferred mixer attributes
+ mAudioService.dispatchPreferredMixerAttributesChanged(
+ new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA).build(),
+ info.getId(),
+ null /*mixerAttributes*/);
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index c8f282fd576e..34457b09ce17 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -22,6 +22,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
import android.media.AudioDevicePort;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -532,6 +533,18 @@ public class AudioDeviceInventory {
.set(MediaMetrics.Property.STATE,
wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
? MediaMetrics.Value.DISCONNECTED : MediaMetrics.Value.CONNECTED);
+ AudioDeviceInfo info = null;
+ if (wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
+ && AudioSystem.DEVICE_OUT_ALL_USB_SET.contains(
+ wdcs.mAttributes.getInternalType())) {
+ for (AudioDeviceInfo deviceInfo : AudioManager.getDevicesStatic(
+ AudioManager.GET_DEVICES_OUTPUTS)) {
+ if (deviceInfo.getInternalType() == wdcs.mAttributes.getInternalType()) {
+ info = deviceInfo;
+ break;
+ }
+ }
+ }
synchronized (mDevicesLock) {
if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
&& DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
@@ -556,6 +569,11 @@ public class AudioDeviceInventory {
if (type == AudioSystem.DEVICE_OUT_HDMI) {
mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);
}
+ if (wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
+ && AudioSystem.DEVICE_OUT_ALL_USB_SET.contains(
+ wdcs.mAttributes.getInternalType())) {
+ mDeviceBroker.dispatchPreferredMixerAttributesChangedCausedByDeviceRemoved(info);
+ }
sendDeviceConnectionIntent(type, wdcs.mState,
wdcs.mAttributes.getAddress(), wdcs.mAttributes.getName());
updateAudioRoutes(type, wdcs.mState);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 09cd8a6dfc38..fb6511c7b321 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -17,6 +17,7 @@
package com.android.server.audio;
import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
+import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT;
import static android.media.AudioManager.RINGER_MODE_NORMAL;
import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
@@ -45,6 +46,7 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.app.IUidObserver;
import android.app.NotificationManager;
import android.app.role.OnRoleHoldersChangedListener;
@@ -88,6 +90,7 @@ import android.media.AudioFormat;
import android.media.AudioHalVersionInfo;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
+import android.media.AudioMixerAttributes;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
@@ -104,6 +107,7 @@ import android.media.ICommunicationDeviceDispatcher;
import android.media.IDeviceVolumeBehaviorDispatcher;
import android.media.IMuteAwaitConnectionCallback;
import android.media.IPlaybackConfigDispatcher;
+import android.media.IPreferredMixerAttributesDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.ISpatializerCallback;
@@ -176,6 +180,7 @@ import android.widget.Toast;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
@@ -376,6 +381,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_FOLD_UPDATE = 49;
private static final int MSG_RESET_SPATIALIZER = 50;
private static final int MSG_NO_LOG_FOR_PLAYER_I = 51;
+ private static final int MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES = 52;
/** Messages handled by the {@link SoundDoseHelper}. */
/*package*/ static final int SAFE_MEDIA_VOLUME_MSG_START = 1000;
@@ -1699,6 +1705,7 @@ public class AudioService extends IAudioService.Stub
}
mSpatializerHelper.reset(/* featureEnabled */ mHasSpatializerEffect);
+ mSoundDoseHelper.reset();
onIndicateSystemReady();
// indicate the end of reconfiguration phase to audio HAL
@@ -4376,7 +4383,7 @@ public class AudioService extends IAudioService.Stub
}
}
- private void sendBroadcastToAll(Intent intent) {
+ private void sendBroadcastToAll(Intent intent, Bundle options) {
if (!mSystemServer.isPrivileged()) {
return;
}
@@ -4384,7 +4391,8 @@ public class AudioService extends IAudioService.Stub
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long ident = Binder.clearCallingIdentity();
try {
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ null /* receiverPermission */, options);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6535,7 +6543,7 @@ public class AudioService extends IAudioService.Stub
Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
- sendBroadcastToAll(broadcast);
+ sendBroadcastToAll(broadcast, null /* options */);
}
}
@@ -6566,6 +6574,20 @@ public class AudioService extends IAudioService.Stub
handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
}
+ private static void sendBundleMsg(Handler handler, int msg,
+ int existingMsgPolicy, int arg1, int arg2, Object obj, Bundle bundle, int delay) {
+ if (existingMsgPolicy == SENDMSG_REPLACE) {
+ handler.removeMessages(msg);
+ } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+ return;
+ }
+
+ final long time = SystemClock.uptimeMillis() + delay;
+ Message message = handler.obtainMessage(msg, arg1, arg2, obj);
+ message.setData(bundle);
+ handler.sendMessageAtTime(message, time);
+ }
+
boolean checkAudioSettingsPermission(String method) {
if (callingOrSelfHasAudioSettingsPermission()) {
return true;
@@ -7560,7 +7582,9 @@ public class AudioService extends IAudioService.Stub
}
};
private final Intent mVolumeChanged;
+ private final Bundle mVolumeChangedOptions;
private final Intent mStreamDevicesChanged;
+ private final Bundle mStreamDevicesChangedOptions;
private VolumeStreamState(String settingName, int streamType) {
mVolumeIndexSettingName = settingName;
@@ -7582,8 +7606,21 @@ public class AudioService extends IAudioService.Stub
readSettings();
mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+ final BroadcastOptions volumeChangedOptions = BroadcastOptions.makeBasic();
+ // This allows us to discard older broadcasts still waiting to be delivered
+ // which have the same namespace (VOLUME_CHANGED_ACTION) and key (mStreamType).
+ volumeChangedOptions.setDeliveryGroupPolicy(DELIVERY_GROUP_POLICY_MOST_RECENT);
+ volumeChangedOptions.setDeliveryGroupMatchingKey(
+ AudioManager.VOLUME_CHANGED_ACTION, String.valueOf(mStreamType));
+ mVolumeChangedOptions = volumeChangedOptions.toBundle();
+
mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+ final BroadcastOptions streamDevicesChangedOptions = BroadcastOptions.makeBasic();
+ streamDevicesChangedOptions.setDeliveryGroupPolicy(DELIVERY_GROUP_POLICY_MOST_RECENT);
+ streamDevicesChangedOptions.setDeliveryGroupMatchingKey(
+ AudioManager.STREAM_DEVICES_CHANGED_ACTION, String.valueOf(mStreamType));
+ mStreamDevicesChangedOptions = streamDevicesChangedOptions.toBundle();
}
/**
@@ -7632,11 +7669,14 @@ public class AudioService extends IAudioService.Stub
}
// send STREAM_DEVICES_CHANGED_ACTION on the message handler so it is scheduled after
// the postObserveDevicesForStreams is handled
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mStreamDevicesChanged;
+ args.arg2 = mStreamDevicesChangedOptions;
sendMsg(mAudioHandler,
MSG_STREAM_DEVICES_CHANGED,
SENDMSG_QUEUE, prevDevices /*arg1*/, devices /*arg2*/,
// ok to send reference to this object, it is final
- mStreamDevicesChanged /*obj*/, 0 /*delay*/);
+ args /*obj*/, 0 /*delay*/);
return mObservedDeviceSet;
}
@@ -7861,7 +7901,7 @@ public class AudioService extends IAudioService.Stub
mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
mStreamVolumeAlias[mStreamType]);
- sendBroadcastToAll(mVolumeChanged);
+ sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions);
}
}
return changed;
@@ -7989,7 +8029,7 @@ public class AudioService extends IAudioService.Stub
Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
- sendBroadcastToAll(intent);
+ sendBroadcastToAll(intent, null /* options */);
}
return changed;
}
@@ -8466,9 +8506,14 @@ public class AudioService extends IAudioService.Stub
break;
case MSG_STREAM_DEVICES_CHANGED:
- sendBroadcastToAll(((Intent) msg.obj)
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final Intent intent = (Intent) args.arg1;
+ final Bundle options = (Bundle) args.arg2;
+ args.recycle();
+ sendBroadcastToAll(intent
.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, msg.arg1)
- .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, msg.arg2));
+ .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, msg.arg2),
+ options);
break;
case MSG_UPDATE_VOLUME_STATES_FOR_DEVICE:
@@ -8531,6 +8576,10 @@ public class AudioService extends IAudioService.Stub
mPlaybackMonitor.ignorePlayerIId(msg.arg1);
break;
+ case MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES:
+ onDispatchPreferredMixerAttributesChanged(msg.getData(), msg.arg1);
+ break;
+
default:
if (msg.what >= SAFE_MEDIA_VOLUME_MSG_START) {
// msg could be for the SoundDoseHelper
@@ -10995,6 +11044,125 @@ public class AudioService extends IAudioService.Stub
}
}
+ /**
+ * @see AudioManager#setPreferredMixerAttributes(
+ * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
+ */
+ public int setPreferredMixerAttributes(AudioAttributes attributes,
+ int portId, AudioMixerAttributes mixerAttributes) {
+ Objects.requireNonNull(attributes);
+ Objects.requireNonNull(mixerAttributes);
+ if (!checkAudioSettingsPermission("setPreferredMixerAttributes()")) {
+ return AudioSystem.PERMISSION_DENIED;
+ }
+ final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
+ int status = AudioSystem.SUCCESS;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final String logString = TextUtils.formatSimple(
+ "setPreferredMixerAttributes u/pid:%d/%d attr:%s mixerAttributes:%s portId:%d",
+ uid, pid, attributes.toString(), mixerAttributes.toString(), portId);
+ sDeviceLogger.enqueue(new EventLogger.StringEvent(logString).printLog(TAG));
+
+ status = mAudioSystem.setPreferredMixerAttributes(
+ attributes, portId, uid, mixerAttributes);
+ if (status == AudioSystem.SUCCESS) {
+ dispatchPreferredMixerAttributesChanged(attributes, portId, mixerAttributes);
+ } else {
+ Log.e(TAG, TextUtils.formatSimple("Error %d in %s)", status, logString));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return status;
+ }
+
+ /**
+ * @see AudioManager#clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
+ */
+ public int clearPreferredMixerAttributes(AudioAttributes attributes, int portId) {
+ Objects.requireNonNull(attributes);
+ if (!checkAudioSettingsPermission("clearPreferredMixerAttributes()")) {
+ return AudioSystem.PERMISSION_DENIED;
+ }
+ final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
+ int status = AudioSystem.SUCCESS;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final String logString = TextUtils.formatSimple(
+ "clearPreferredMixerAttributes u/pid:%d/%d attr:%s",
+ uid, pid, attributes.toString());
+ sDeviceLogger.enqueue(new EventLogger.StringEvent(logString).printLog(TAG));
+
+ status = mAudioSystem.clearPreferredMixerAttributes(attributes, portId, uid);
+ if (status == AudioSystem.SUCCESS) {
+ dispatchPreferredMixerAttributesChanged(attributes, portId, null /*mixerAttr*/);
+ } else {
+ Log.e(TAG, TextUtils.formatSimple("Error %d in %s)", status, logString));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return status;
+ }
+
+ void dispatchPreferredMixerAttributesChanged(
+ AudioAttributes attr, int deviceId, AudioMixerAttributes mixerAttr) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_AUDIO_ATTRIBUTES, attr);
+ bundle.putParcelable(KEY_AUDIO_MIXER_ATTRIBUTES, mixerAttr);
+ sendBundleMsg(mAudioHandler, MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES, SENDMSG_QUEUE,
+ deviceId, 0, null, bundle, 0);
+ }
+
+ final RemoteCallbackList<IPreferredMixerAttributesDispatcher> mPrefMixerAttrDispatcher =
+ new RemoteCallbackList<IPreferredMixerAttributesDispatcher>();
+ private static final String KEY_AUDIO_ATTRIBUTES = "audio_attributes";
+ private static final String KEY_AUDIO_MIXER_ATTRIBUTES = "audio_mixer_attributes";
+
+ /** @see AudioManager#addOnPreferredMixerAttributesChangedListener(
+ * Executor, AudioManager.OnPreferredMixerAttributesChangedListener)
+ */
+ public void registerPreferredMixerAttributesDispatcher(
+ @Nullable IPreferredMixerAttributesDispatcher dispatcher) {
+ if (dispatcher == null) {
+ return;
+ }
+ mPrefMixerAttrDispatcher.register(dispatcher);
+ }
+
+ /** @see AudioManager#removeOnPreferredMixerAttributesChangedListener(
+ * AudioManager.OnPreferredMixerAttributesChangedListener)
+ */
+ public void unregisterPreferredMixerAttributesDispatcher(
+ @Nullable IPreferredMixerAttributesDispatcher dispatcher) {
+ if (dispatcher == null) {
+ return;
+ }
+ mPrefMixerAttrDispatcher.unregister(dispatcher);
+ }
+
+ protected void onDispatchPreferredMixerAttributesChanged(Bundle data, int deviceId) {
+ final int nbDispathers = mPrefMixerAttrDispatcher.beginBroadcast();
+ final AudioAttributes attr = data.getParcelable(
+ KEY_AUDIO_ATTRIBUTES, AudioAttributes.class);
+ final AudioMixerAttributes mixerAttr = data.getParcelable(
+ KEY_AUDIO_MIXER_ATTRIBUTES, AudioMixerAttributes.class);
+ for (int i = 0; i < nbDispathers; i++) {
+ try {
+ mPrefMixerAttrDispatcher.getBroadcastItem(i)
+ .dispatchPrefMixerAttributesChanged(attr, deviceId, mixerAttr);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't call dispatchPrefMixerAttributesChanged() "
+ + "IPreferredMixerAttributesDispatcher "
+ + mPrefMixerAttrDispatcher.getBroadcastItem(i).asBinder(), e);
+ }
+ }
+ mPrefMixerAttrDispatcher.finishBroadcast();
+ }
+
private final Object mExtVolumeControllerLock = new Object();
private IAudioPolicyCallback mExtVolumeController;
private void setExtVolumeController(IAudioPolicyCallback apc) {
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 558daa183afa..1d25e31ab8e2 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -20,7 +20,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
+import android.media.AudioMixerAttributes;
import android.media.AudioSystem;
+import android.media.ISoundDose;
import android.media.ISoundDoseCallback;
import android.media.audiopolicy.AudioMix;
import android.os.SystemClock;
@@ -496,12 +498,42 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
}
/**
- * Same as {@link AudioSystem#registerSoundDoseCallback(ISoundDoseCallback)}
+ * Same as {@link AudioSystem#getSoundDoseInterface(ISoundDoseCallback)}
* @param callback
* @return
*/
- public int registerSoundDoseCallback(ISoundDoseCallback callback) {
- return AudioSystem.registerSoundDoseCallback(callback);
+ public ISoundDose getSoundDoseInterface(ISoundDoseCallback callback) {
+ return AudioSystem.getSoundDoseInterface(callback);
+ }
+
+ /**
+ * Same as
+ * {@link AudioSystem#setPreferredMixerAttributes(
+ * AudioAttributes, int, int, AudioMixerAttributes)}
+ * @param attributes
+ * @param mixerAttributes
+ * @param uid
+ * @param portId
+ * @return
+ */
+ public int setPreferredMixerAttributes(
+ @NonNull AudioAttributes attributes,
+ int portId,
+ int uid,
+ @NonNull AudioMixerAttributes mixerAttributes) {
+ return AudioSystem.setPreferredMixerAttributes(attributes, portId, uid, mixerAttributes);
+ }
+
+ /**
+ * Same as {@link AudioSystem#clearPreferredMixerAttributes(AudioAttributes, int, int)}
+ * @param attributes
+ * @param uid
+ * @param portId
+ * @return
+ */
+ public int clearPreferredMixerAttributes(
+ @NonNull AudioAttributes attributes, int portId, int uid) {
+ return AudioSystem.clearPreferredMixerAttributes(attributes, portId, uid);
}
/**
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index ff6a7f103ce9..0d0de8ad2886 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -27,10 +27,12 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.AudioSystem;
+import android.media.ISoundDose;
import android.media.ISoundDoseCallback;
import android.media.SoundDoseRecord;
import android.os.Binder;
import android.os.Message;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -43,8 +45,10 @@ import com.android.server.audio.AudioService.AudioHandler;
import com.android.server.audio.AudioService.ISafeHearingVolumeController;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -88,6 +92,8 @@ public class SoundDoseHelper {
private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
private static final int REQUEST_CODE_CHECK_MUSIC_ACTIVE = 1;
+ private static final float CUSTOM_RS2_VALUE = 90;
+
private int mMcc = 0;
final Object mSafeMediaVolumeStateLock = new Object();
@@ -131,6 +137,10 @@ public class SoundDoseHelper {
@NonNull private final AudioHandler mAudioHandler;
@NonNull private final ISafeHearingVolumeController mVolumeController;
+ private ISoundDose mSoundDose;
+ private float mCurrentCsd = 0.f;
+ private final List<SoundDoseRecord> mDoseRecords = new ArrayList<>();
+
private final Context mContext;
private final ISoundDoseCallback.Stub mSoundDoseCallback = new ISoundDoseCallback.Stub() {
@@ -141,6 +151,8 @@ public class SoundDoseHelper {
public void onNewCsdValue(float currentCsd, SoundDoseRecord[] records) {
Log.i(TAG, "onNewCsdValue: " + currentCsd);
+ mCurrentCsd = currentCsd;
+ mDoseRecords.addAll(Arrays.asList(records));
for (SoundDoseRecord record : records) {
Log.i(TAG, " new record: csd=" + record.value
+ " averageMel=" + record.averageMel + " timestamp=" + record.timestamp
@@ -162,10 +174,6 @@ public class SoundDoseHelper {
mSafeMediaVolumeState = mSettings.getGlobalInt(audioService.getContentResolver(),
Settings.Global.AUDIO_SAFE_VOLUME_STATE, 0);
- if (USE_CSD_FOR_SAFE_HEARING) {
- AudioSystem.registerSoundDoseCallback(mSoundDoseCallback);
- mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
- }
// The default safe volume index read here will be replaced by the actual value when
// the mcc is read by onConfigureSafeVolume()
@@ -174,6 +182,8 @@ public class SoundDoseHelper {
mAlarmManager = (AlarmManager) mContext.getSystemService(
Context.ALARM_SERVICE);
+
+ initCsd();
}
/*package*/ int safeMediaVolumeIndex(int device) {
@@ -392,6 +402,35 @@ public class SoundDoseHelper {
pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
}
+ /*package*/void reset() {
+ Log.d(TAG, "Reset the sound dose helper");
+ initCsd();
+ }
+
+ private void initCsd() {
+ synchronized (mSafeMediaVolumeStateLock) {
+ if (USE_CSD_FOR_SAFE_HEARING) {
+ Log.v(TAG, "Initializing sound dose");
+
+ mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
+ mSoundDose = AudioSystem.getSoundDoseInterface(mSoundDoseCallback);
+ try {
+ if (mSoundDose != null && mSoundDose.asBinder().isBinderAlive()) {
+ mSoundDose.setOutputRs2(CUSTOM_RS2_VALUE);
+ if (mCurrentCsd != 0.f) {
+ Log.d(TAG, "Resetting the saved sound dose value " + mCurrentCsd);
+ SoundDoseRecord[] records = mDoseRecords.toArray(
+ new SoundDoseRecord[0]);
+ mSoundDose.resetCsd(mCurrentCsd, records);
+ }
+ }
+ } catch (RemoteException e) {
+ // noop
+ }
+ }
+ }
+ }
+
private void onConfigureSafeVolume(boolean force, String caller) {
synchronized (mSafeMediaVolumeStateLock) {
int mcc = mContext.getResources().getConfiguration().mcc;
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index d2e572f2f979..218be9de5ffb 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -18,7 +18,6 @@ package com.android.server.companion.virtual;
import android.annotation.NonNull;
import android.companion.virtual.IVirtualDevice;
-import android.companion.virtual.VirtualDeviceParams;
import java.util.Set;
@@ -94,12 +93,6 @@ public abstract class VirtualDeviceManagerInternal {
public abstract int getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice);
/**
- * Returns true if the given {@code uid} is the owner of any virtual devices that are
- * currently active.
- */
- public abstract boolean isAppOwnerOfAnyVirtualDevice(int uid);
-
- /**
* Returns true if the given {@code uid} is currently running on any virtual devices. This is
* determined by whether the app has any activities in the task stack on a virtual-device-owned
* display.
@@ -110,14 +103,4 @@ public abstract class VirtualDeviceManagerInternal {
* Returns true if the {@code displayId} is owned by any virtual device
*/
public abstract boolean isDisplayOwnedByAnyVirtualDevice(int displayId);
-
- /**
- * Returns the device policy for the given virtual device and policy type.
- *
- * <p>In case the virtual device identifier is not valid, or there's no explicitly specified
- * policy for that device and policy type, then
- * {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT} is returned.
- */
- public abstract @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
- int deviceId, @VirtualDeviceParams.PolicyType int policyType);
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index c1e9526a9127..98a0af7f7c15 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -36,16 +36,19 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.server.display.config.AutoBrightness;
+import com.android.server.display.config.BlockingZoneConfig;
import com.android.server.display.config.BrightnessThresholds;
import com.android.server.display.config.BrightnessThrottlingMap;
import com.android.server.display.config.BrightnessThrottlingPoint;
import com.android.server.display.config.Density;
+import com.android.server.display.config.DisplayBrightnessPoint;
import com.android.server.display.config.DisplayConfiguration;
import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HighBrightnessMode;
import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
+import com.android.server.display.config.RefreshRateConfigs;
import com.android.server.display.config.RefreshRateRange;
import com.android.server.display.config.SdrHdrRatioMap;
import com.android.server.display.config.SdrHdrRatioPoint;
@@ -130,6 +133,35 @@ import javax.xml.datatype.DatatypeConfigurationException;
* </brightnessThrottlingMap>
* </thermalThrottling>
*
+ * <refreshRate>
+ * <lowerBlockingZoneConfigs>
+ * <defaultRefreshRate>75</defaultRefreshRate>
+ * <blockingZoneThreshold>
+ * <displayBrightnessPoint>
+ * <lux>50</lux>
+ * <nits>45.3</nits>
+ * </displayBrightnessPoint>
+ * <displayBrightnessPoint>
+ * <lux>60</lux>
+ * <nits>55.2</nits>
+ * </displayBrightnessPoint>
+ * </blockingZoneThreshold>
+ * </lowerBlockingZoneConfigs>
+ * <higherBlockingZoneConfigs>
+ * <defaultRefreshRate>90</defaultRefreshRate>
+ * <blockingZoneThreshold>
+ * <displayBrightnessPoint>
+ * <lux>500</lux>
+ * <nits>245.3</nits>
+ * </displayBrightnessPoint>
+ * <displayBrightnessPoint>
+ * <lux>600</lux>
+ * <nits>232.3</nits>
+ * </displayBrightnessPoint>
+ * </blockingZoneThreshold>
+ * </higherBlockingZoneConfigs>
+ * </refreshRate>
+ *
* <highBrightnessMode enabled="true">
* <transitionPoint>0.62</transitionPoint>
* <minimumLux>10000</minimumLux>
@@ -358,6 +390,9 @@ public class DisplayDeviceConfig {
private static final String STABLE_ID_SUFFIX_FORMAT = "id_%d";
private static final String NO_SUFFIX_FORMAT = "%d";
private static final long STABLE_FLAG = 1L << 62;
+ private static final int DEFAULT_LOW_REFRESH_RATE = 60;
+ private static final int DEFAULT_HIGH_REFRESH_RATE = 0;
+ private static final int[] DEFAULT_BRIGHTNESS_THRESHOLDS = new int[]{};
private static final float[] DEFAULT_AMBIENT_THRESHOLD_LEVELS = new float[]{0f};
private static final float[] DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS = new float[]{100f};
@@ -512,6 +547,49 @@ public class DisplayDeviceConfig {
// This stores the raw value loaded from the config file - true if not written.
private boolean mDdcAutoBrightnessAvailable = true;
+ /**
+ * The default peak refresh rate for a given device. This value prevents the framework from
+ * using higher refresh rates, even if display modes with higher refresh rates are available
+ * from hardware composer. Only has an effect if the value is non-zero.
+ */
+ private int mDefaultHighRefreshRate = DEFAULT_HIGH_REFRESH_RATE;
+
+ /**
+ * The default refresh rate for a given device. This value sets the higher default
+ * refresh rate. If the hardware composer on the device supports display modes with
+ * a higher refresh rate than the default value specified here, the framework may use those
+ * higher refresh rate modes if an app chooses one by setting preferredDisplayModeId or calling
+ * setFrameRate(). We have historically allowed fallback to mDefaultHighRefreshRate if
+ * mDefaultLowRefreshRate is set to 0, but this is not supported anymore.
+ */
+ private int mDefaultLowRefreshRate = DEFAULT_LOW_REFRESH_RATE;
+
+ /**
+ * The display uses different gamma curves for different refresh rates. It's hard for panel
+ * vendors to tune the curves to have exact same brightness for different refresh rate. So
+ * brightness flickers could be observed at switch time. The issue is worse at the gamma lower
+ * end. In addition, human eyes are more sensitive to the flicker at darker environment. To
+ * prevent flicker, we only support higher refresh rates if the display brightness is above a
+ * threshold. For example, no higher refresh rate if display brightness <= disp0 && ambient
+ * brightness <= amb0 || display brightness <= disp1 && ambient brightness <= amb1
+ */
+ private int[] mLowDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
+ private int[] mLowAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
+
+ /**
+ * The display uses different gamma curves for different refresh rates. It's hard for panel
+ * vendors to tune the curves to have exact same brightness for different refresh rate. So
+ * brightness flickers could be observed at switch time. The issue can be observed on the screen
+ * with even full white content at the high brightness. To prevent flickering, we support fixed
+ * refresh rates if the display and ambient brightness are equal to or above the provided
+ * thresholds. You can define multiple threshold levels as higher brightness environments may
+ * have lower display brightness requirements for the flickering is visible. For example, fixed
+ * refresh rate if display brightness >= disp0 && ambient brightness >= amb0 || display
+ * brightness >= disp1 && ambient brightness >= amb1
+ */
+ private int[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
+ private int[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
+
// Brightness Throttling data may be updated via the DeviceConfig. Here we store the original
// data, which comes from the ddc, and the current one, which may be the DeviceConfig
// overwritten value.
@@ -1195,15 +1273,15 @@ public class DisplayDeviceConfig {
/**
* @return Default peak refresh rate of the associated display
*/
- public int getDefaultPeakRefreshRate() {
- return mContext.getResources().getInteger(R.integer.config_defaultPeakRefreshRate);
+ public int getDefaultHighRefreshRate() {
+ return mDefaultHighRefreshRate;
}
/**
* @return Default refresh rate of the associated display
*/
- public int getDefaultRefreshRate() {
- return mContext.getResources().getInteger(R.integer.config_defaultRefreshRate);
+ public int getDefaultLowRefreshRate() {
+ return mDefaultLowRefreshRate;
}
/**
@@ -1212,8 +1290,7 @@ public class DisplayDeviceConfig {
* allowed
*/
public int[] getLowDisplayBrightnessThresholds() {
- return mContext.getResources().getIntArray(
- R.array.config_brightnessThresholdsOfPeakRefreshRate);
+ return mLowDisplayBrightnessThresholds;
}
/**
@@ -1222,8 +1299,7 @@ public class DisplayDeviceConfig {
* allowed
*/
public int[] getLowAmbientBrightnessThresholds() {
- return mContext.getResources().getIntArray(
- R.array.config_ambientThresholdsOfPeakRefreshRate);
+ return mLowAmbientBrightnessThresholds;
}
/**
@@ -1232,8 +1308,7 @@ public class DisplayDeviceConfig {
* allowed
*/
public int[] getHighDisplayBrightnessThresholds() {
- return mContext.getResources().getIntArray(
- R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+ return mHighDisplayBrightnessThresholds;
}
/**
@@ -1242,8 +1317,7 @@ public class DisplayDeviceConfig {
* allowed
*/
public int[] getHighAmbientBrightnessThresholds() {
- return mContext.getResources().getIntArray(
- R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+ return mHighAmbientBrightnessThresholds;
}
@Override
@@ -1335,6 +1409,17 @@ public class DisplayDeviceConfig {
+ ", mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits)
+ ", mDdcAutoBrightnessAvailable= " + mDdcAutoBrightnessAvailable
+ ", mAutoBrightnessAvailable= " + mAutoBrightnessAvailable
+ + "\n"
+ + ", mDefaultRefreshRate= " + mDefaultLowRefreshRate
+ + ", mDefaultPeakRefreshRate= " + mDefaultHighRefreshRate
+ + ", mLowDisplayBrightnessThresholds= "
+ + Arrays.toString(mLowDisplayBrightnessThresholds)
+ + ", mLowAmbientBrightnessThresholds= "
+ + Arrays.toString(mLowAmbientBrightnessThresholds)
+ + ", mHighDisplayBrightnessThresholds= "
+ + Arrays.toString(mHighDisplayBrightnessThresholds)
+ + ", mHighAmbientBrightnessThresholds= "
+ + Arrays.toString(mHighAmbientBrightnessThresholds)
+ "}";
}
@@ -1392,6 +1477,7 @@ public class DisplayDeviceConfig {
loadAmbientHorizonFromDdc(config);
loadBrightnessChangeThresholds(config);
loadAutoBrightnessConfigValues(config);
+ loadRefreshRateSetting(config);
} else {
Slog.w(TAG, "DisplayDeviceConfig file is null");
}
@@ -1414,6 +1500,7 @@ public class DisplayDeviceConfig {
setProxSensorUnspecified();
loadAutoBrightnessConfigsFromConfigXml();
loadAutoBrightnessAvailableFromConfigXml();
+ loadRefreshRateSetting(null);
mLoadedFrom = "<config.xml>";
}
@@ -1624,6 +1711,143 @@ public class DisplayDeviceConfig {
}
}
+ private void loadRefreshRateSetting(DisplayConfiguration config) {
+ final RefreshRateConfigs refreshRateConfigs =
+ (config == null) ? null : config.getRefreshRate();
+ BlockingZoneConfig lowerBlockingZoneConfig =
+ (refreshRateConfigs == null) ? null
+ : refreshRateConfigs.getLowerBlockingZoneConfigs();
+ BlockingZoneConfig higherBlockingZoneConfig =
+ (refreshRateConfigs == null) ? null
+ : refreshRateConfigs.getHigherBlockingZoneConfigs();
+ loadLowerRefreshRateBlockingZones(lowerBlockingZoneConfig);
+ loadHigherRefreshRateBlockingZones(higherBlockingZoneConfig);
+ }
+
+
+ /**
+ * Loads the refresh rate configurations pertaining to the upper blocking zones.
+ */
+ private void loadLowerRefreshRateBlockingZones(BlockingZoneConfig lowerBlockingZoneConfig) {
+ loadLowerBlockingZoneDefaultRefreshRate(lowerBlockingZoneConfig);
+ loadLowerBrightnessThresholds(lowerBlockingZoneConfig);
+ }
+
+ /**
+ * Loads the refresh rate configurations pertaining to the upper blocking zones.
+ */
+ private void loadHigherRefreshRateBlockingZones(BlockingZoneConfig upperBlockingZoneConfig) {
+ loadHigherBlockingZoneDefaultRefreshRate(upperBlockingZoneConfig);
+ loadHigherBrightnessThresholds(upperBlockingZoneConfig);
+ }
+
+ /**
+ * Loads the default peak refresh rate. Internally, this takes care of loading
+ * the value from the display config, and if not present, falls back to config.xml.
+ */
+ private void loadHigherBlockingZoneDefaultRefreshRate(
+ BlockingZoneConfig upperBlockingZoneConfig) {
+ if (upperBlockingZoneConfig == null) {
+ mDefaultHighRefreshRate = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultPeakRefreshRate);
+ } else {
+ mDefaultHighRefreshRate =
+ upperBlockingZoneConfig.getDefaultRefreshRate().intValue();
+ }
+ }
+
+ /**
+ * Loads the default refresh rate. Internally, this takes care of loading
+ * the value from the display config, and if not present, falls back to config.xml.
+ */
+ private void loadLowerBlockingZoneDefaultRefreshRate(
+ BlockingZoneConfig lowerBlockingZoneConfig) {
+ if (lowerBlockingZoneConfig == null) {
+ mDefaultLowRefreshRate = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultRefreshRate);
+ } else {
+ mDefaultLowRefreshRate =
+ lowerBlockingZoneConfig.getDefaultRefreshRate().intValue();
+ }
+ }
+
+ /**
+ * Loads the lower brightness thresholds for refresh rate switching. Internally, this takes care
+ * of loading the value from the display config, and if not present, falls back to config.xml.
+ */
+ private void loadLowerBrightnessThresholds(BlockingZoneConfig lowerBlockingZoneConfig) {
+ if (lowerBlockingZoneConfig == null) {
+ mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_brightnessThresholdsOfPeakRefreshRate);
+ mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_ambientThresholdsOfPeakRefreshRate);
+ if (mLowDisplayBrightnessThresholds == null || mLowAmbientBrightnessThresholds == null
+ || mLowDisplayBrightnessThresholds.length
+ != mLowAmbientBrightnessThresholds.length) {
+ throw new RuntimeException("display low brightness threshold array and ambient "
+ + "brightness threshold array have different length: "
+ + "mLowDisplayBrightnessThresholds="
+ + Arrays.toString(mLowDisplayBrightnessThresholds)
+ + ", mLowAmbientBrightnessThresholds="
+ + Arrays.toString(mLowAmbientBrightnessThresholds));
+ }
+ } else {
+ List<DisplayBrightnessPoint> lowerThresholdDisplayBrightnessPoints =
+ lowerBlockingZoneConfig.getBlockingZoneThreshold().getDisplayBrightnessPoint();
+ int size = lowerThresholdDisplayBrightnessPoints.size();
+ mLowDisplayBrightnessThresholds = new int[size];
+ mLowAmbientBrightnessThresholds = new int[size];
+ for (int i = 0; i < size; i++) {
+ // We are explicitly casting this value to an integer to be able to reuse the
+ // existing DisplayBrightnessPoint type. It is fine to do this because the round off
+ // will have the negligible and unnoticeable impact on the loaded thresholds.
+ mLowDisplayBrightnessThresholds[i] = (int) lowerThresholdDisplayBrightnessPoints
+ .get(i).getNits().floatValue();
+ mLowAmbientBrightnessThresholds[i] = lowerThresholdDisplayBrightnessPoints
+ .get(i).getLux().intValue();
+ }
+ }
+ }
+
+ /**
+ * Loads the higher brightness thresholds for refresh rate switching. Internally, this takes
+ * care of loading the value from the display config, and if not present, falls back to
+ * config.xml.
+ */
+ private void loadHigherBrightnessThresholds(BlockingZoneConfig blockingZoneConfig) {
+ if (blockingZoneConfig == null) {
+ mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+ mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+ if (mHighAmbientBrightnessThresholds == null || mHighDisplayBrightnessThresholds == null
+ || mHighAmbientBrightnessThresholds.length
+ != mHighDisplayBrightnessThresholds.length) {
+ throw new RuntimeException("display high brightness threshold array and ambient "
+ + "brightness threshold array have different length: "
+ + "mHighDisplayBrightnessThresholds="
+ + Arrays.toString(mHighDisplayBrightnessThresholds)
+ + ", mHighAmbientBrightnessThresholds="
+ + Arrays.toString(mHighAmbientBrightnessThresholds));
+ }
+ } else {
+ List<DisplayBrightnessPoint> higherThresholdDisplayBrightnessPoints =
+ blockingZoneConfig.getBlockingZoneThreshold().getDisplayBrightnessPoint();
+ int size = higherThresholdDisplayBrightnessPoints.size();
+ mHighDisplayBrightnessThresholds = new int[size];
+ mHighAmbientBrightnessThresholds = new int[size];
+ for (int i = 0; i < size; i++) {
+ // We are explicitly casting this value to an integer to be able to reuse the
+ // existing DisplayBrightnessPoint type. It is fine to do this because the round off
+ // will have the negligible and unnoticeable impact on the loaded thresholds.
+ mHighDisplayBrightnessThresholds[i] = (int) higherThresholdDisplayBrightnessPoints
+ .get(i).getNits().floatValue();
+ mHighAmbientBrightnessThresholds[i] = higherThresholdDisplayBrightnessPoints
+ .get(i).getLux().intValue();
+ }
+ }
+ }
+
private void loadAutoBrightnessConfigValues(DisplayConfiguration config) {
final AutoBrightness autoBrightness = config.getAutoBrightness();
loadAutoBrightnessBrighteningLightDebounce(autoBrightness);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ae84e96f4c2f..c700ccbdc0a1 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1414,12 +1414,20 @@ public final class DisplayManagerService extends SystemService {
// LogicalDisplayMapper aware of the link between the new display and its associated virtual
// device before triggering DISPLAY_DEVICE_EVENT_ADDED.
if ((flags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
- try {
- final int virtualDeviceId = virtualDevice.getDeviceId();
- mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(
- device, virtualDeviceId);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ if (virtualDevice != null) {
+ try {
+ final int virtualDeviceId = virtualDevice.getDeviceId();
+ mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(
+ device, virtualDeviceId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.i(
+ TAG,
+ "Display created with VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP set, but no"
+ + " virtual device. The display will not be added to a device display"
+ + " group.");
}
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 405a2b958dd1..5dba015b72be 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -1358,7 +1358,7 @@ public class DisplayModeDirector {
mDefaultRefreshRate =
(displayDeviceConfig == null) ? (float) mContext.getResources().getInteger(
R.integer.config_defaultRefreshRate)
- : (float) displayDeviceConfig.getDefaultRefreshRate();
+ : (float) displayDeviceConfig.getDefaultLowRefreshRate();
}
public void observe() {
@@ -1445,7 +1445,7 @@ public class DisplayModeDirector {
defaultPeakRefreshRate =
(displayDeviceConfig == null) ? (float) mContext.getResources().getInteger(
R.integer.config_defaultPeakRefreshRate)
- : (float) displayDeviceConfig.getDefaultPeakRefreshRate();
+ : (float) displayDeviceConfig.getDefaultHighRefreshRate();
}
mDefaultPeakRefreshRate = defaultPeakRefreshRate;
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index ea096299cf48..b8225419cb9b 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -378,6 +378,10 @@ public final class DreamManagerService extends SystemService {
return false;
}
+ if (!dreamsEnabledForUser(ActivityManager.getCurrentUser())) {
+ return false;
+ }
+
if ((mWhenToDream & DREAM_ON_CHARGE) == DREAM_ON_CHARGE) {
return mIsCharging;
}
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 87fe785ca614..b8e7d4971790 100644
--- a/services/core/java/com/android/server/incident/IncidentCompanionService.java
+++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java
@@ -34,7 +34,6 @@ import android.os.IncidentManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.UserManager;
import android.util.Log;
import com.android.internal.util.DumpUtils;
@@ -128,21 +127,21 @@ public class IncidentCompanionService extends SystemService {
try {
final Context context = getContext();
- final int primaryUser = getAndValidateUser(context);
- if (primaryUser == UserHandle.USER_NULL) {
+ // Get the current admin user. Only they can do incident reports.
+ final int currentAdminUser = getCurrentUserIfAdmin();
+ if (currentAdminUser == UserHandle.USER_NULL) {
return;
}
final Intent intent = new Intent(Intent.ACTION_INCIDENT_REPORT_READY);
intent.setComponent(new ComponentName(pkg, cls));
- Log.d(TAG, "sendReportReadyBroadcast sending primaryUser=" + primaryUser
- + " userHandle=" + UserHandle.getUserHandleForUid(primaryUser)
+ Log.d(TAG, "sendReportReadyBroadcast sending currentUser=" + currentAdminUser
+ + " userHandle=" + UserHandle.of(currentAdminUser)
+ " intent=" + intent);
- // Send it to the primary user. Only they can do incident reports.
context.sendBroadcastAsUserMultiplePermissions(intent,
- UserHandle.getUserHandleForUid(primaryUser),
+ UserHandle.of(currentAdminUser),
DUMP_AND_USAGE_STATS_PERMISSIONS);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -414,10 +413,10 @@ public class IncidentCompanionService extends SystemService {
}
/**
- * Check whether the current user is the primary user, and return the user id if they are.
+ * Check whether the current user is an admin user, and return the user id if they are.
* Returns UserHandle.USER_NULL if not valid.
*/
- public static int getAndValidateUser(Context context) {
+ public static int getCurrentUserIfAdmin() {
// Current user
UserInfo currentUser;
try {
@@ -427,28 +426,21 @@ public class IncidentCompanionService extends SystemService {
throw new RuntimeException(ex);
}
- // Primary user
- final UserManager um = UserManager.get(context);
- final UserInfo primaryUser = um.getPrimaryUser();
-
// Check that we're using the right user.
if (currentUser == null) {
Log.w(TAG, "No current user. Nobody to approve the report."
+ " The report will be denied.");
return UserHandle.USER_NULL;
}
- if (primaryUser == null) {
- Log.w(TAG, "No primary user. Nobody to approve the report."
- + " The report will be denied.");
- return UserHandle.USER_NULL;
- }
- if (primaryUser.id != currentUser.id) {
- Log.w(TAG, "Only the primary user can approve bugreports, but they are not"
- + " the current user. The report will be denied.");
+
+ if (!currentUser.isAdmin()) {
+ Log.w(TAG, "Only an admin user running in foreground can approve "
+ + "bugreports, but the current foreground user is not an admin user. "
+ + "The report will be denied.");
return UserHandle.USER_NULL;
}
- return primaryUser.id;
+ return currentUser.id;
}
}
diff --git a/services/core/java/com/android/server/incident/PendingReports.java b/services/core/java/com/android/server/incident/PendingReports.java
index f39bebf060f7..6285bc3f531b 100644
--- a/services/core/java/com/android/server/incident/PendingReports.java
+++ b/services/core/java/com/android/server/incident/PendingReports.java
@@ -16,6 +16,7 @@
package com.android.server.incident;
+import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.content.ComponentName;
@@ -272,15 +273,19 @@ class PendingReports {
return;
}
- // Find the primary user of this device.
- final int primaryUser = getAndValidateUser();
- if (primaryUser == UserHandle.USER_NULL) {
+ // Find the current user of the device and check if they are an admin.
+ final int currentAdminUser = getCurrentUserIfAdmin();
+
+ // Deny the report if the current admin user is null
+ // or not the user who requested the report.
+ if (currentAdminUser == UserHandle.USER_NULL
+ || currentAdminUser != UserHandle.getUserId(callingUid)) {
denyReportBeforeAddingRec(listener, callingPackage);
return;
}
// Find the approver app (hint: it's PermissionController).
- final ComponentName receiver = getApproverComponent(primaryUser);
+ final ComponentName receiver = getApproverComponent(currentAdminUser);
if (receiver == null) {
// We couldn't find an approver... so deny the request here and now, before we
// do anything else.
@@ -298,26 +303,26 @@ class PendingReports {
try {
listener.asBinder().linkToDeath(() -> {
Log.i(TAG, "Got death notification listener=" + listener);
- cancelReportImpl(listener, receiver, primaryUser);
+ cancelReportImpl(listener, receiver, currentAdminUser);
}, 0);
} catch (RemoteException ex) {
Log.e(TAG, "Remote died while trying to register death listener: " + rec.getUri());
// First, remove from our list.
- cancelReportImpl(listener, receiver, primaryUser);
+ cancelReportImpl(listener, receiver, currentAdminUser);
}
// Go tell Permission controller to start asking the user.
- sendBroadcast(receiver, primaryUser);
+ sendBroadcast(receiver, currentAdminUser);
}
/**
* Cancel a pending report request (because of an explicit call to cancel)
*/
private void cancelReportImpl(IIncidentAuthListener listener) {
- final int primaryUser = getAndValidateUser();
- final ComponentName receiver = getApproverComponent(primaryUser);
- if (primaryUser != UserHandle.USER_NULL && receiver != null) {
- cancelReportImpl(listener, receiver, primaryUser);
+ final int currentAdminUser = getCurrentUserIfAdmin();
+ final ComponentName receiver = getApproverComponent(currentAdminUser);
+ if (currentAdminUser != UserHandle.USER_NULL && receiver != null) {
+ cancelReportImpl(listener, receiver, currentAdminUser);
}
}
@@ -326,13 +331,13 @@ class PendingReports {
* by the calling app, or because of a binder death).
*/
private void cancelReportImpl(IIncidentAuthListener listener, ComponentName receiver,
- int primaryUser) {
+ @UserIdInt int user) {
// First, remove from our list.
synchronized (mLock) {
removePendingReportRecLocked(listener);
}
// Second, call back to PermissionController to say it's canceled.
- sendBroadcast(receiver, primaryUser);
+ sendBroadcast(receiver, user);
}
/**
@@ -342,21 +347,21 @@ class PendingReports {
* cleanup cases to keep the apps' list in sync with ours.
*/
private void sendBroadcast() {
- final int primaryUser = getAndValidateUser();
- if (primaryUser == UserHandle.USER_NULL) {
+ final int currentAdminUser = getCurrentUserIfAdmin();
+ if (currentAdminUser == UserHandle.USER_NULL) {
return;
}
- final ComponentName receiver = getApproverComponent(primaryUser);
+ final ComponentName receiver = getApproverComponent(currentAdminUser);
if (receiver == null) {
return;
}
- sendBroadcast(receiver, primaryUser);
+ sendBroadcast(receiver, currentAdminUser);
}
/**
* Send the confirmation broadcast.
*/
- private void sendBroadcast(ComponentName receiver, int primaryUser) {
+ private void sendBroadcast(ComponentName receiver, int currentUser) {
final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED);
intent.setComponent(receiver);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -364,8 +369,8 @@ class PendingReports {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setBackgroundActivityStartsAllowed(true);
- // Send it to the primary user.
- mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(primaryUser),
+ // Send it to the current user.
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(currentUser),
android.Manifest.permission.APPROVE_INCIDENT_REPORTS, options.toBundle());
}
@@ -420,11 +425,11 @@ class PendingReports {
}
/**
- * Check whether the current user is the primary user, and return the user id if they are.
+ * Check whether the current user is an admin user, and return the user id if they are.
* Returns UserHandle.USER_NULL if not valid.
*/
- private int getAndValidateUser() {
- return IncidentCompanionService.getAndValidateUser(mContext);
+ private int getCurrentUserIfAdmin() {
+ return IncidentCompanionService.getCurrentUserIfAdmin();
}
/**
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 0da04a22d31f..c62abf004daa 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1193,7 +1193,7 @@ public class InputManagerService extends IInputManager.Stub
@Override // Binder call
public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype) {
+ @Nullable InputMethodSubtype imeSubtype) {
return mKeyboardLayoutManager.getKeyboardLayoutForInputDevice(identifier, userId,
imeInfo, imeSubtype);
}
@@ -1202,16 +1202,16 @@ public class InputManagerService extends IInputManager.Stub
@Override // Binder call
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) {
+ @Nullable InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) {
super.setKeyboardLayoutForInputDevice_enforcePermission();
mKeyboardLayoutManager.setKeyboardLayoutForInputDevice(identifier, userId, imeInfo,
imeSubtype, keyboardLayoutDescriptor);
}
@Override // Binder call
- public String[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
+ public KeyboardLayout[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype) {
+ @Nullable InputMethodSubtype imeSubtype) {
return mKeyboardLayoutManager.getKeyboardLayoutListForInputDevice(identifier, userId,
imeInfo, imeSubtype);
}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 1bb14aa6c438..d76da8326335 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -17,6 +17,7 @@
package com.android.server.input;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Notification;
import android.app.NotificationManager;
@@ -550,7 +551,7 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype) {
+ @Nullable InputMethodSubtype imeSubtype) {
// TODO(b/259530132): Implement the new keyboard layout API: Returning non-IME specific
// layout for now.
return getCurrentKeyboardLayoutForInputDevice(identifier);
@@ -558,23 +559,18 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) {
+ @Nullable InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) {
// TODO(b/259530132): Implement the new keyboard layout API: setting non-IME specific
// layout for now.
setCurrentKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
}
- public String[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
+ public KeyboardLayout[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
- @NonNull InputMethodSubtype imeSubtype) {
+ @Nullable InputMethodSubtype imeSubtype) {
// TODO(b/259530132): Implement the new keyboard layout API: Returning list of all
// layouts for now.
- KeyboardLayout[] allLayouts = getKeyboardLayouts();
- String[] allLayoutDesc = new String[allLayouts.length];
- for (int i = 0; i < allLayouts.length; i++) {
- allLayoutDesc[i] = allLayouts[i].getDescriptor();
- }
- return allLayoutDesc;
+ return getKeyboardLayouts();
}
public void switchKeyboardLayout(int deviceId, int direction) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index ebf9237d61ea..be99bfbc2bc9 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -199,9 +199,14 @@ final class InputMethodUtils {
}
/**
- * Utility class for putting and getting settings for InputMethod
+ * Utility class for putting and getting settings for InputMethod.
+ *
+ * This is used in two ways:
+ * - Singleton instance in {@link InputMethodManagerService}, which is updated on user-switch to
+ * follow the current user.
+ * - On-demand instances when we need settings for non-current users.
+ *
* TODO: Move all putters and getters of settings to this class.
- * TODO(b/235661780): Make the setting supports multi-users.
*/
@UserHandleAware
public static class InputMethodSettings {
@@ -212,9 +217,9 @@ final class InputMethodUtils {
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR);
@NonNull
- private final Context mUserAwareContext;
- private final Resources mRes;
- private final ContentResolver mResolver;
+ private Context mUserAwareContext;
+ private Resources mRes;
+ private ContentResolver mResolver;
private final ArrayMap<String, InputMethodInfo> mMethodMap;
/**
@@ -272,15 +277,19 @@ final class InputMethodUtils {
return imsList;
}
- InputMethodSettings(@NonNull Context context,
- ArrayMap<String, InputMethodInfo> methodMap, @UserIdInt int userId,
- boolean copyOnWrite) {
+ private void initContentWithUserContext(@NonNull Context context, @UserIdInt int userId) {
mUserAwareContext = context.getUserId() == userId
? context
: context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
mRes = mUserAwareContext.getResources();
mResolver = mUserAwareContext.getContentResolver();
+ }
+
+ InputMethodSettings(@NonNull Context context,
+ ArrayMap<String, InputMethodInfo> methodMap, @UserIdInt int userId,
+ boolean copyOnWrite) {
mMethodMap = methodMap;
+ initContentWithUserContext(context, userId);
switchCurrentUser(userId, copyOnWrite);
}
@@ -301,6 +310,9 @@ final class InputMethodUtils {
mEnabledInputMethodsStrCache = "";
// TODO: mCurrentProfileIds should be cleared here.
}
+ if (mUserAwareContext.getUserId() != userId) {
+ initContentWithUserContext(mUserAwareContext, userId);
+ }
mCurrentUserId = userId;
mCopyOnWrite = copyOnWrite;
// TODO: mCurrentProfileIds should be updated here.
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 3ce51c3d1412..b4c959693311 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -24,6 +24,7 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.BLOCK_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_HARDWARE_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
@@ -95,6 +96,7 @@ import android.util.IndentingPrintWriter;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
@@ -319,6 +321,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
for (LocationProviderManager manager : mProviderManagers) {
if (providerName.equals(manager.getName())) {
+ if (!manager.isVisibleToCaller()) {
+ return null;
+ }
return manager;
}
}
@@ -341,8 +346,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
}
- private void addLocationProviderManager(LocationProviderManager manager,
- @Nullable AbstractLocationProvider realProvider) {
+ @VisibleForTesting
+ void addLocationProviderManager(
+ LocationProviderManager manager, @Nullable AbstractLocationProvider realProvider) {
synchronized (mProviderManagers) {
Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);
@@ -453,6 +459,20 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
if (gnssProvider == null) {
gnssProvider = mGnssManagerService.getGnssLocationProvider();
+ } else {
+ // If we have a GNSS provider override, add the hardware provider as a standalone
+ // option for use by apps with the correct permission. Note the GNSS HAL can only
+ // support a single client, so mGnssManagerService.getGnssLocationProvider() can
+ // only be installed with a single provider.
+ LocationProviderManager gnssHardwareManager =
+ new LocationProviderManager(
+ mContext,
+ mInjector,
+ GPS_HARDWARE_PROVIDER,
+ mPassiveManager,
+ Collections.singletonList(Manifest.permission.LOCATION_HARDWARE));
+ addLocationProviderManager(
+ gnssHardwareManager, mGnssManagerService.getGnssLocationProvider());
}
LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
@@ -629,7 +649,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
public List<String> getAllProviders() {
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
for (LocationProviderManager manager : mProviderManagers) {
- providers.add(manager.getName());
+ if (manager.isVisibleToCaller()) {
+ providers.add(manager.getName());
+ }
}
return providers;
}
@@ -644,15 +666,18 @@ public class LocationManagerService extends ILocationManager.Stub implements
synchronized (mLock) {
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
for (LocationProviderManager manager : mProviderManagers) {
- String name = manager.getName();
- if (enabledOnly && !manager.isEnabled(UserHandle.getCallingUserId())) {
- continue;
- }
- if (criteria != null && !LocationProvider.propertiesMeetCriteria(name,
- manager.getProperties(), criteria)) {
- continue;
+ if (manager.isVisibleToCaller()) {
+ String name = manager.getName();
+ if (enabledOnly && !manager.isEnabled(UserHandle.getCallingUserId())) {
+ continue;
+ }
+ if (criteria != null
+ && !LocationProvider.propertiesMeetCriteria(
+ name, manager.getProperties(), criteria)) {
+ continue;
+ }
+ providers.add(name);
}
- providers.add(name);
}
return providers;
}
@@ -1059,7 +1084,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
public void addProviderRequestListener(IProviderRequestListener listener) {
mContext.enforceCallingOrSelfPermission(INTERACT_ACROSS_USERS, null);
for (LocationProviderManager manager : mProviderManagers) {
- manager.addProviderRequestListener(listener);
+ if (manager.isVisibleToCaller()) {
+ manager.addProviderRequestListener(listener);
+ }
}
}
@@ -1649,7 +1676,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
- if (identity.equals(manager.getProviderIdentity())) {
+ if (identity.equals(manager.getProviderIdentity()) && manager.isVisibleToCaller()) {
return true;
}
}
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 7063cb80d514..ffdb53142567 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -19,6 +19,7 @@ package com.android.server.location.provider;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.app.compat.CompatChanges.isChangeEnabled;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.KEY_FLUSH_COMPLETE;
@@ -48,6 +49,7 @@ import static java.lang.Math.min;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.AlarmManager.OnAlarmListener;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
@@ -124,6 +126,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -1362,6 +1365,10 @@ public class LocationProviderManager extends
@GuardedBy("mMultiplexerLock")
private final ArrayList<ProviderEnabledListener> mEnabledListeners;
+ // Extra permissions required to use this provider (on top of the usual location permissions).
+ // Not guarded because it's read only.
+ private final Collection<String> mRequiredPermissions;
+
private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
protected final LocationManagerInternal mLocationManagerInternal;
@@ -1435,12 +1442,34 @@ public class LocationProviderManager extends
public LocationProviderManager(Context context, Injector injector,
String name, @Nullable PassiveLocationProviderManager passiveManager) {
+ this(context, injector, name, passiveManager, Collections.emptyList());
+ }
+
+ /**
+ * Creates a manager for a location provider (the two have a 1:1 correspondence).
+ *
+ * @param context Context in which the manager is running.
+ * @param injector Injector to retrieve system components (useful to override in testing)
+ * @param name Name of this provider (used in LocationManager APIs by client apps).
+ * @param passiveManager The "passive" manager (special case provider that returns locations
+ * from all other providers).
+ * @param requiredPermissions Required permissions for accessing this provider. All of the given
+ * permissions are required to access the provider. If a caller doesn't hold the correct
+ * permission, the provider will be invisible to it.
+ */
+ public LocationProviderManager(
+ Context context,
+ Injector injector,
+ String name,
+ @Nullable PassiveLocationProviderManager passiveManager,
+ Collection<String> requiredPermissions) {
mContext = context;
mName = Objects.requireNonNull(name);
mPassiveManager = passiveManager;
mState = STATE_STOPPED;
mEnabled = new SparseBooleanArray(2);
mLastLocations = new SparseArray<>(2);
+ mRequiredPermissions = requiredPermissions;
mEnabledListeners = new ArrayList<>();
mProviderRequestListeners = new CopyOnWriteArrayList<>();
@@ -1559,6 +1588,24 @@ public class LocationProviderManager extends
}
}
+ /**
+ * Returns true if this provider is visible to the current caller (whether called from a binder
+ * thread or not). If a provider isn't visible, then all APIs return the same data they would if
+ * the provider didn't exist (i.e. the caller can't see or use the provider).
+ *
+ * <p>This method doesn't require any permissions, but uses permissions to determine which
+ * subset of providers are visible.
+ */
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ public boolean isVisibleToCaller() {
+ for (String permission : mRequiredPermissions) {
+ if (mContext.checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public void addEnabledListener(ProviderEnabledListener listener) {
synchronized (mMultiplexerLock) {
Preconditions.checkState(mState != STATE_STOPPED);
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 58428ca48c97..2fdc4cd5f7c1 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -33,8 +33,8 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.UserManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
@@ -189,10 +189,10 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
}
/**
- * Validates that the current user is the primary user or when bugreport is requested remotely
- * and current user is affiliated user.
+ * Validates that the current user is an admin user or, when bugreport is requested remotely
+ * that the current user is an affiliated user.
*
- * @throws IllegalArgumentException if the current user is not the primary user
+ * @throws IllegalArgumentException if the current user is not an admin user
*/
private void ensureUserCanTakeBugReport(int bugreportMode) {
UserInfo currentUser = null;
@@ -202,20 +202,17 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
// Impossible to get RemoteException for an in-process call.
}
- UserInfo primaryUser = UserManager.get(mContext).getPrimaryUser();
if (currentUser == null) {
- logAndThrow("No current user. Only primary user is allowed to take bugreports.");
+ logAndThrow("There is no current user, so no bugreport can be requested.");
}
- if (primaryUser == null) {
- logAndThrow("No primary user. Only primary user is allowed to take bugreports.");
- }
- if (primaryUser.id != currentUser.id) {
+
+ if (!currentUser.isAdmin()) {
if (bugreportMode == BugreportParams.BUGREPORT_MODE_REMOTE
&& isCurrentUserAffiliated(currentUser.id)) {
return;
}
- logAndThrow("Current user not primary user. Only primary user"
- + " is allowed to take bugreports.");
+ logAndThrow(TextUtils.formatSimple("Current user %s is not an admin user."
+ + " Only admin users are allowed to take bugreport.", currentUser.id));
}
}
diff --git a/services/core/java/com/android/server/pm/CloneProfileResolver.java b/services/core/java/com/android/server/pm/CloneProfileResolver.java
index d3113e12abe3..73036f12327a 100644
--- a/services/core/java/com/android/server/pm/CloneProfileResolver.java
+++ b/services/core/java/com/android/server/pm/CloneProfileResolver.java
@@ -18,6 +18,8 @@ package com.android.server.pm;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.provider.DeviceConfig;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.resolution.ComponentResolverApi;
@@ -32,6 +34,30 @@ import java.util.function.Function;
*/
public class CloneProfileResolver extends CrossProfileResolver {
+ /**
+ * Feature flag to allow/restrict intent redirection from/to clone profile.
+ * Default value is false,this is to ensure that framework is not impacted by intent redirection
+ * till we are ready to launch.
+ * From Android U onwards, this would be set to true and eventually removed.
+ * @hide
+ */
+ private static final String FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE =
+ "allow_intent_redirection_for_clone_profile";
+
+ /**
+ * Returns true if intent redirection for clone profile feature flag is set
+ * @return value of flag allow_intent_redirection_for_clone_profile
+ */
+ public static boolean isIntentRedirectionForCloneProfileAllowed() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
+ FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, false /* defaultValue */);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
public CloneProfileResolver(ComponentResolverApi componentResolver,
UserManagerService userManagerService) {
super(componentResolver, userManagerService);
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 5b8ee2b085cc..60621a0eaaef 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -338,6 +338,9 @@ public interface Computer extends PackageDataSnapshot {
@NonNull
ArrayMap<String, ? extends PackageStateInternal> getPackageStates();
+ @NonNull
+ ArrayMap<String, ? extends PackageStateInternal> getDisabledSystemPackageStates();
+
@Nullable
String getRenamedPackage(@NonNull String packageName);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 45b633f02e50..b8fba51c4d60 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -185,6 +185,10 @@ public class ComputerEngine implements Computer {
return mSettings.getPackagesLocked().untrackedStorage();
}
+ public ArrayMap<String, ? extends PackageStateInternal> getDisabledSystemPackages() {
+ return mSettings.getDisabledSystemPackagesLocked().untrackedStorage();
+ }
+
public Settings(@NonNull com.android.server.pm.Settings settings) {
mSettings = settings;
}
@@ -3459,6 +3463,12 @@ public class ComputerEngine implements Computer {
return mSettings.getPackages();
}
+ @NonNull
+ @Override
+ public ArrayMap<String, ? extends PackageStateInternal> getDisabledSystemPackageStates() {
+ return mSettings.getDisabledSystemPackages();
+ }
+
@Nullable
@Override
public String getRenamedPackage(@NonNull String packageName) {
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java
new file mode 100644
index 000000000000..e682586314ac
--- /dev/null
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
+import android.util.ArraySet;
+
+/**
+ * Helper class to manage {@link com.android.server.pm.CrossProfileIntentFilter}s.
+ */
+public class CrossProfileIntentFilterHelper {
+ private Context mContext;
+ private UserManagerInternal mUserManagerInternal;
+ private Settings mSettings;
+ private UserManagerService mUserManagerService;
+ private PackageManagerTracedLock mLock;
+
+ public CrossProfileIntentFilterHelper(Settings settings, UserManagerService userManagerService,
+ PackageManagerTracedLock lock, UserManagerInternal userManagerInternal,
+ Context context) {
+ mSettings = settings;
+ mUserManagerService = userManagerService;
+ mLock = lock;
+ mContext = context;
+ mUserManagerInternal = userManagerInternal;
+ }
+
+ /**
+ * For users that have
+ * {@link android.content.pm.UserProperties#getUpdateCrossProfileIntentFiltersOnOTA} set, this
+ * task will update default {@link com.android.server.pm.CrossProfileIntentFilter} between that
+ * user and its parent. This will only update CrossProfileIntentFilters set by system package.
+ * The new default are configured in {@link UserTypeDetails}.
+ */
+ public void updateDefaultCrossProfileIntentFilter() {
+ for (UserInfo userInfo : mUserManagerInternal.getUsers(false)) {
+
+ UserProperties currentUserProperties = mUserManagerInternal
+ .getUserProperties(userInfo.id);
+
+ if (currentUserProperties.getUpdateCrossProfileIntentFiltersOnOTA()) {
+ int parentUserId = mUserManagerInternal.getProfileParentId(userInfo.id);
+ if (parentUserId != userInfo.id) {
+ clearCrossProfileIntentFilters(userInfo.id,
+ mContext.getOpPackageName(), parentUserId);
+ clearCrossProfileIntentFilters(parentUserId,
+ mContext.getOpPackageName(), userInfo.id);
+
+ mUserManagerInternal.setDefaultCrossProfileIntentFilters(parentUserId,
+ userInfo.id);
+ }
+ }
+ }
+ }
+
+ /**
+ * Clear {@link CrossProfileIntentFilter}s configured on source user by ownerPackage
+ * targeting the targetUserId. If targetUserId is null then it will clear
+ * {@link CrossProfileIntentFilter} for any target user.
+ * @param sourceUserId source user for whom CrossProfileIntentFilter would be configured
+ * @param ownerPackage package who would have configured CrossProfileIntentFilter
+ * @param targetUserId user id for which CrossProfileIntentFilter will be removed.
+ * This can be null in which case it will clear for any target user.
+ */
+ public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage,
+ Integer targetUserId) {
+ synchronized (mLock) {
+ CrossProfileIntentResolver resolver = mSettings
+ .editCrossProfileIntentResolverLPw(sourceUserId);
+ ArraySet<CrossProfileIntentFilter> set =
+ new ArraySet<>(resolver.filterSet());
+ for (CrossProfileIntentFilter filter : set) {
+ //Only remove if calling user is allowed based on access control of
+ // {@link CrossProfileIntentFilter}
+ if (filter.getOwnerPackage().equals(ownerPackage)
+ && (targetUserId == null || filter.mTargetUserId == targetUserId)
+ && mUserManagerService.isCrossProfileIntentFilterAccessible(sourceUserId,
+ filter.mTargetUserId, /* addCrossProfileIntentFilter */ false)) {
+ resolver.removeFilter(filter);
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
index 5d97cb7c61ae..1e0822d6bd63 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
@@ -32,7 +32,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.os.Process;
import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -250,8 +249,7 @@ public class CrossProfileIntentResolverEngine {
* SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE is enabled
*/
if (sourceUserInfo.isCloneProfile() || targetUserInfo.isCloneProfile()) {
- if (FeatureFlagUtils.isEnabled(mContext,
- FeatureFlagUtils.SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE)) {
+ if (CloneProfileResolver.isIntentRedirectionForCloneProfileAllowed()) {
return new CloneProfileResolver(computer.getComponentResolver(),
mUserManager);
} else {
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 12b5ab8a3160..823bc7122943 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -39,6 +39,8 @@ import android.annotation.Nullable;
import android.os.Environment;
import android.os.SystemClock;
import android.os.Trace;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Slog;
@@ -55,6 +57,7 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArrayMap;
import java.io.File;
+import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
@@ -227,6 +230,24 @@ final class InitAppsHelper {
}
/**
+ * Fix up the previously-installed app directory mode - they can't be readable by non-system
+ * users to prevent them from listing the dir to discover installed package names.
+ */
+ void fixInstalledAppDirMode() {
+ try (var files = Files.newDirectoryStream(mPm.getAppInstallDir().toPath())) {
+ files.forEach(dir -> {
+ try {
+ Os.chmod(dir.toString(), 0771);
+ } catch (ErrnoException e) {
+ Slog.w(TAG, "Failed to fix an installed app dir mode", e);
+ }
+ });
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to walk the app install directory to fix the modes", e);
+ }
+ }
+
+ /**
* Install apps/updates from data dir and fix system apps that are affected.
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
@@ -234,6 +255,11 @@ final class InitAppsHelper {
long startTime) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
+
+ if ((mScanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == SCAN_FIRST_BOOT_OR_UPGRADE) {
+ fixInstalledAppDirMode();
+ }
+
scanDirTracedLI(mPm.getAppInstallDir(), 0,
mScanFlags | SCAN_REQUIRE_KNOWN, packageParser, mExecutorService);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 61052f59c93b..911cfbd7f2c3 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1720,7 +1720,7 @@ final class InstallPackageHelper {
final boolean onIncremental = mPm.mIncrementalManager != null
&& isIncrementalPath(beforeCodeFile.getAbsolutePath());
try {
- makeDirRecursive(afterCodeFile.getParentFile(), 0775);
+ makeDirRecursive(afterCodeFile.getParentFile(), 0771);
if (onIncremental) {
// Just link files here. The stage dir will be removed when the installation
// session is completed.
@@ -2242,6 +2242,7 @@ final class InstallPackageHelper {
@GuardedBy("mPm.mInstallLock")
private void executePostCommitStepsLIF(List<ReconciledPackage> reconciledPackages) {
final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
+ final ArrayList<String> apkPaths = new ArrayList<>();
for (ReconciledPackage reconciledPkg : reconciledPackages) {
final InstallRequest installRequest = reconciledPkg.mInstallRequest;
final boolean instantApp = ((installRequest.getScanFlags() & SCAN_AS_INSTANT_APP) != 0);
@@ -2261,25 +2262,11 @@ final class InstallPackageHelper {
}
// Enabling fs-verity is a blocking operation. To reduce the impact to the install time,
- // run in a background thread.
- final ArrayList<String> apkPaths = new ArrayList<>();
+ // collect the files to later enable in a background thread.
apkPaths.add(pkg.getBaseApkPath());
if (pkg.getSplitCodePaths() != null) {
Collections.addAll(apkPaths, pkg.getSplitCodePaths());
}
- mInjector.getBackgroundHandler().post(() -> {
- try {
- for (String path : apkPaths) {
- if (!VerityUtils.hasFsverity(path)) {
- VerityUtils.setUpFsverity(path, (byte[]) null);
- }
- }
- } catch (IOException e) {
- // There's nothing we can do if the setup failed. Since fs-verity is
- // optional, just ignore the error for now.
- Slog.e(TAG, "Failed to fully enable fs-verity to " + packageName);
- }
- });
// Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
mAppDataHelper.prepareAppDataPostCommitLIF(pkg, 0);
@@ -2393,6 +2380,20 @@ final class InstallPackageHelper {
}
PackageManagerServiceUtils.waitForNativeBinariesExtractionForIncremental(
incrementalStorages);
+
+ mInjector.getBackgroundHandler().post(() -> {
+ for (String path : apkPaths) {
+ if (!VerityUtils.hasFsverity(path)) {
+ try {
+ VerityUtils.setUpFsverity(path, (byte[]) null);
+ } catch (IOException e) {
+ // There's nothing we can do if the setup failed. Since fs-verity is
+ // optional, just ignore the error for now.
+ Slog.e(TAG, "Failed to fully enable fs-verity to " + path);
+ }
+ }
+ }
+ });
}
Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
diff --git a/services/core/java/com/android/server/pm/PackageManagerLocal.java b/services/core/java/com/android/server/pm/PackageManagerLocal.java
index d163d3d7a085..935c4ddd2597 100644
--- a/services/core/java/com/android/server/pm/PackageManagerLocal.java
+++ b/services/core/java/com/android/server/pm/PackageManagerLocal.java
@@ -149,6 +149,16 @@ public interface PackageManagerLocal {
@NonNull
Map<String, PackageState> getPackageStates();
+ /**
+ * Returns a map of all disabled system {@link PackageState PackageStates} on the device.
+ *
+ * @return Mapping of package name to disabled system {@link PackageState}.
+ *
+ * @hide Pending API
+ */
+ @NonNull
+ Map<String, PackageState> getDisabledSystemPackageStates();
+
@Override
void close();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 91f7011c90c7..e6e2f7988493 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1537,7 +1537,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
(i, pm) -> new BackgroundDexOptService(i.getContext(), i.getDexManager(), pm),
(i, pm) -> IBackupManager.Stub.asInterface(ServiceManager.getService(
Context.BACKUP_SERVICE)),
- (i, pm) -> new SharedLibrariesImpl(pm, i));
+ (i, pm) -> new SharedLibrariesImpl(pm, i),
+ (i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(),
+ i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(),
+ context));
if (Build.VERSION.SDK_INT <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
@@ -2029,13 +2032,21 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final WatchedArrayMap<String, PackageSetting> packageSettings =
mSettings.getPackagesLocked();
- // Save the names of pre-existing packages prior to scanning, so we can determine
- // which system packages are completely new due to an upgrade.
if (isDeviceUpgrading()) {
+ // Save the names of pre-existing packages prior to scanning, so we can determine
+ // which system packages are completely new due to an upgrade.
mExistingPackages = new ArraySet<>(packageSettings.size());
for (PackageSetting ps : packageSettings.values()) {
mExistingPackages.add(ps.getPackageName());
}
+
+ // Triggering {@link com.android.server.pm.crossprofile.
+ // CrossProfileIntentFilterHelper.updateDefaultCrossProfileIntentFilter} to update
+ // {@link CrossProfileIntentFilter}s between eligible users and their parent
+ t.traceBegin("cross profile intent filter update");
+ mInjector.getCrossProfileIntentFilterHelper()
+ .updateDefaultCrossProfileIntentFilter();
+ t.traceEnd();
}
mCacheDir = PackageManagerServiceUtils.preparePackageParserCache(
@@ -3448,6 +3459,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
scheduleWritePackageRestrictions(sourceUserId);
}
+
// Enforcing that callingUid is owning pkg on userId
private void enforceOwnerRights(@NonNull Computer snapshot, String pkg, int callingUid) {
// The system owns everything.
@@ -4638,21 +4650,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
enforceOwnerRights(snapshot, ownerPackage, callingUid);
PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
- synchronized (mLock) {
- CrossProfileIntentResolver resolver =
- mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
- ArraySet<CrossProfileIntentFilter> set =
- new ArraySet<>(resolver.filterSet());
- for (CrossProfileIntentFilter filter : set) {
- //Only remove if calling user is allowed based on access control of
- // {@link CrossProfileIntentFilter}
- if (filter.getOwnerPackage().equals(ownerPackage)
- && mUserManager.isCrossProfileIntentFilterAccessible(sourceUserId,
- filter.mTargetUserId, /* addCrossProfileIntentFilter */ false)) {
- resolver.removeFilter(filter);
- }
- }
- }
+ PackageManagerService.this.mInjector.getCrossProfileIntentFilterHelper()
+ .clearCrossProfileIntentFilters(sourceUserId, ownerPackage,
+ null);
scheduleWritePackageRestrictions(sourceUserId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
index 396994b04514..76e6e45fc873 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
@@ -139,6 +139,7 @@ public class PackageManagerServiceInjector {
private final Singleton<BackgroundDexOptService> mBackgroundDexOptService;
private final Singleton<IBackupManager> mIBackupManager;
private final Singleton<SharedLibrariesImpl> mSharedLibrariesProducer;
+ private final Singleton<CrossProfileIntentFilterHelper> mCrossProfileIntentFilterHelperProducer;
PackageManagerServiceInjector(Context context, PackageManagerTracedLock lock,
Installer installer, Object installLock, PackageAbiHelper abiHelper,
@@ -176,7 +177,8 @@ public class PackageManagerServiceInjector {
ServiceProducer getSystemServiceProducer,
Producer<BackgroundDexOptService> backgroundDexOptService,
Producer<IBackupManager> iBackupManager,
- Producer<SharedLibrariesImpl> sharedLibrariesProducer) {
+ Producer<SharedLibrariesImpl> sharedLibrariesProducer,
+ Producer<CrossProfileIntentFilterHelper> crossProfileIntentFilterHelperProducer) {
mContext = context;
mLock = lock;
mInstaller = installer;
@@ -228,6 +230,8 @@ public class PackageManagerServiceInjector {
mBackgroundDexOptService = new Singleton<>(backgroundDexOptService);
mIBackupManager = new Singleton<>(iBackupManager);
mSharedLibrariesProducer = new Singleton<>(sharedLibrariesProducer);
+ mCrossProfileIntentFilterHelperProducer = new Singleton<>(
+ crossProfileIntentFilterHelperProducer);
}
/**
@@ -262,6 +266,14 @@ public class PackageManagerServiceInjector {
return mLock;
}
+ /**
+ * {@link CrossProfileIntentFilterHelper} which manages {@link CrossProfileIntentFilter}
+ * @return CrossProfileIntentFilterHelper
+ */
+ public CrossProfileIntentFilterHelper getCrossProfileIntentFilterHelper() {
+ return mCrossProfileIntentFilterHelperProducer.get(this, mPackageManager);
+ }
+
public Installer getInstaller() {
return mInstaller;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e1efc612224c..2138c205ee58 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -99,7 +99,6 @@ import android.system.Os;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.IntArray;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -116,6 +115,7 @@ import com.android.server.SystemConfig;
import com.android.server.art.ArtManagerLocal;
import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+import com.android.server.pm.permission.PermissionAllowlist;
import com.android.server.pm.verify.domain.DomainVerificationShell;
import dalvik.system.DexFile;
@@ -2684,26 +2684,7 @@ class PackageManagerShellCommand extends ShellCommand {
getErrPrintWriter().println("Error: no package specified.");
return 1;
}
-
- ArraySet<String> privAppPermissions = null;
- if (isVendorApp(pkg)) {
- privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg);
- } else if (isProductApp(pkg)) {
- privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg);
- } else if (isSystemExtApp(pkg)) {
- privAppPermissions = SystemConfig.getInstance()
- .getSystemExtPrivAppPermissions(pkg);
- } else if (isApexApp(pkg)) {
- final String apexName = ApexManager.getInstance().getApexModuleNameForPackageName(
- getApexPackageNameContainingPackage(pkg));
- privAppPermissions = SystemConfig.getInstance()
- .getApexPrivAppPermissions(apexName, pkg);
- } else {
- privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
- }
-
- getOutPrintWriter().println(privAppPermissions == null
- ? "{}" : privAppPermissions.toString());
+ getOutPrintWriter().println(getPrivAppPermissionsString(pkg, true));
return 0;
}
@@ -2713,27 +2694,52 @@ class PackageManagerShellCommand extends ShellCommand {
getErrPrintWriter().println("Error: no package specified.");
return 1;
}
+ getOutPrintWriter().println(getPrivAppPermissionsString(pkg, false));
+ return 0;
+ }
- ArraySet<String> privAppPermissions = null;
- if (isVendorApp(pkg)) {
- privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg);
- } else if (isProductApp(pkg)) {
- privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg);
- } else if (isSystemExtApp(pkg)) {
- privAppPermissions = SystemConfig.getInstance()
- .getSystemExtPrivAppDenyPermissions(pkg);
- } else if (isApexApp(pkg)) {
- final String apexName = ApexManager.getInstance().getApexModuleNameForPackageName(
- getApexPackageNameContainingPackage(pkg));
- privAppPermissions = SystemConfig.getInstance()
- .getApexPrivAppDenyPermissions(apexName, pkg);
+ @NonNull
+ private String getPrivAppPermissionsString(@NonNull String packageName, boolean allowed) {
+ final PermissionAllowlist permissionAllowlist =
+ SystemConfig.getInstance().getPermissionAllowlist();
+ final ArrayMap<String, ArrayMap<String, Boolean>> privAppPermissions;
+ if (isVendorApp(packageName)) {
+ privAppPermissions = permissionAllowlist.getVendorPrivilegedAppAllowlist();
+ } else if (isProductApp(packageName)) {
+ privAppPermissions = permissionAllowlist.getProductPrivilegedAppAllowlist();
+ } else if (isSystemExtApp(packageName)) {
+ privAppPermissions = permissionAllowlist.getSystemExtPrivilegedAppAllowlist();
+ } else if (isApexApp(packageName)) {
+ final String moduleName = ApexManager.getInstance().getApexModuleNameForPackageName(
+ getApexPackageNameContainingPackage(packageName));
+ privAppPermissions = permissionAllowlist.getApexPrivilegedAppAllowlists()
+ .get(moduleName);
} else {
- privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+ privAppPermissions = permissionAllowlist.getPrivilegedAppAllowlist();
+ }
+ final ArrayMap<String, Boolean> permissions = privAppPermissions != null
+ ? privAppPermissions.get(packageName) : null;
+ if (permissions == null) {
+ return "{}";
+ }
+ final StringBuilder result = new StringBuilder("{");
+ boolean isFirstPermission = true;
+ final int permissionsSize = permissions.size();
+ for (int i = 0; i < permissionsSize; i++) {
+ boolean permissionAllowed = permissions.valueAt(i);
+ if (permissionAllowed != allowed) {
+ continue;
+ }
+ if (isFirstPermission) {
+ isFirstPermission = false;
+ } else {
+ result.append(", ");
+ }
+ String permissionName = permissions.keyAt(i);
+ result.append(permissionName);
}
-
- getOutPrintWriter().println(privAppPermissions == null
- ? "{}" : privAppPermissions.toString());
- return 0;
+ result.append("}");
+ return result.toString();
}
private int runGetOemPermissions() {
@@ -2743,7 +2749,7 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
final Map<String, Boolean> oemPermissions = SystemConfig.getInstance()
- .getOemPermissions(pkg);
+ .getPermissionAllowlist().getOemAppAllowlist().get(pkg);
if (oemPermissions == null || oemPermissions.isEmpty()) {
getOutPrintWriter().println("{}");
} else {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 89b74f400919..01dee132a324 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -819,6 +819,10 @@ public final class Settings implements Watchable, Snappable {
return mPackages;
}
+ WatchedArrayMap<String, PackageSetting> getDisabledSystemPackagesLocked() {
+ return mDisabledSysPackages;
+ }
+
KeySetManagerService getKeySetManagerService() {
return mKeySetManagerService;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 5c8992691034..2ae8b52da172 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -59,6 +59,18 @@ public abstract class UserManagerInternal {
})
public @interface UserAssignmentResult {}
+ public static final int USER_START_MODE_FOREGROUND = 1;
+ public static final int USER_START_MODE_BACKGROUND = 2;
+ public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
+
+ private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
+ @IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = {
+ USER_START_MODE_FOREGROUND,
+ USER_START_MODE_BACKGROUND,
+ USER_START_MODE_BACKGROUND_VISIBLE
+ })
+ public @interface UserStartMode {}
+
public interface UserRestrictionsListener {
/**
* Called when a user restriction changes.
@@ -383,8 +395,7 @@ public abstract class UserManagerInternal {
* pass a valid display id.
*/
public abstract @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId,
- @UserIdInt int profileGroupId,
- boolean foreground, int displayId);
+ @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId);
/**
* Unassigns a user from its current display when it's stopping.
@@ -445,6 +456,13 @@ public abstract class UserManagerInternal {
result);
}
+ /**
+ * Gets the user-friendly representation of a user start {@code mode}.
+ */
+ public static String userStartModeToString(@UserStartMode int mode) {
+ return DebugUtils.constantToString(UserManagerInternal.class, PREFIX_USER_START_MODE, mode);
+ }
+
/** Adds a {@link UserVisibilityListener}. */
public abstract void addUserVisibilityListener(UserVisibilityListener listener);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9a6e5d41655a..0a650c912b3e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -127,8 +127,11 @@ import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemService;
import com.android.server.am.UserState;
+import com.android.server.pm.UserManagerInternal.UserAssignmentResult;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
+import com.android.server.pm.UserManagerInternal.UserStartMode;
+import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -6980,8 +6983,11 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public int assignUserToDisplayOnStart(@UserIdInt int userId, @UserIdInt int profileGroupId,
- boolean foreground, int displayId) {
+ @UserAssignmentResult
+ public int assignUserToDisplayOnStart(@UserIdInt int userId,
+ @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId) {
+ // TODO(245939659): change UserVisibilityMediator to take @UserStartMode
+ boolean foreground = userStartMode == UserManagerInternal.USER_START_MODE_FOREGROUND;
return mUserVisibilityMediator.assignUserToDisplayOnStart(userId, profileGroupId,
foreground, displayId);
}
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 8fb5773706c5..2bb72b8cae42 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -132,7 +132,8 @@ public final class UserTypeFactory {
.setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT)
.setShowInSettings(UserProperties.SHOW_IN_SETTINGS_WITH_PARENT)
.setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
- .setUseParentsContacts(true));
+ .setUseParentsContacts(true)
+ .setUpdateCrossProfileIntentFiltersOnOTA(true));
}
/**
diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
index 9b9ca1088064..92e8f55287d4 100644
--- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java
+++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
@@ -139,7 +139,7 @@ public final class UserVisibilityMediator implements Dumpable {
}
/**
- * See {@link UserManagerInternal#assignUserToDisplayOnStart(int, int, boolean, int)}.
+ * See {@link UserManagerInternal#assignUserToDisplayOnStart(int, int, int, int)}.
*/
public @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId,
@UserIdInt int unResolvedProfileGroupId, boolean foreground, int displayId) {
diff --git a/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java b/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java
index f8e154755cff..4e0a11d5a458 100644
--- a/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java
+++ b/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java
@@ -104,6 +104,9 @@ public class PackageManagerLocalImpl implements PackageManagerLocal {
@Nullable
private Map<String, PackageState> mCachedUnmodifiablePackageStates;
+ @Nullable
+ private Map<String, PackageState> mCachedUnmodifiableDisabledSystemPackageStates;
+
private UnfilteredSnapshotImpl(@NonNull PackageDataSnapshot snapshot) {
super(snapshot);
}
@@ -126,10 +129,24 @@ public class PackageManagerLocalImpl implements PackageManagerLocal {
return mCachedUnmodifiablePackageStates;
}
+ @SuppressWarnings("RedundantSuppression")
+ @NonNull
+ @Override
+ public Map<String, PackageState> getDisabledSystemPackageStates() {
+ checkClosed();
+
+ if (mCachedUnmodifiableDisabledSystemPackageStates == null) {
+ mCachedUnmodifiableDisabledSystemPackageStates =
+ Collections.unmodifiableMap(mSnapshot.getDisabledSystemPackageStates());
+ }
+ return mCachedUnmodifiableDisabledSystemPackageStates;
+ }
+
@Override
public void close() {
super.close();
mCachedUnmodifiablePackageStates = null;
+ mCachedUnmodifiableDisabledSystemPackageStates = null;
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java b/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java
new file mode 100644
index 000000000000..3efac81d44e3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+
+/**
+ * Data class for OEM and privileged app permission allowlist state.
+ */
+public final class PermissionAllowlist {
+ @NonNull
+ private final ArrayMap<String, ArrayMap<String, Boolean>> mOemAppAllowlist = new ArrayMap<>();
+ @NonNull
+ private final ArrayMap<String, ArrayMap<String, Boolean>> mPrivilegedAppAllowlist =
+ new ArrayMap<>();
+ @NonNull
+ private final ArrayMap<String, ArrayMap<String, Boolean>> mVendorPrivilegedAppAllowlist =
+ new ArrayMap<>();
+ @NonNull
+ private final ArrayMap<String, ArrayMap<String, Boolean>> mProductPrivilegedAppAllowlist =
+ new ArrayMap<>();
+ @NonNull
+ private final ArrayMap<String, ArrayMap<String, Boolean>> mSystemExtPrivilegedAppAllowlist =
+ new ArrayMap<>();
+ @NonNull
+ private final ArrayMap<String, ArrayMap<String, ArrayMap<String, Boolean>>>
+ mApexPrivilegedAppAllowlists = new ArrayMap<>();
+
+ @NonNull
+ public ArrayMap<String, ArrayMap<String, Boolean>> getOemAppAllowlist() {
+ return mOemAppAllowlist;
+ }
+
+ @NonNull
+ public ArrayMap<String, ArrayMap<String, Boolean>> getPrivilegedAppAllowlist() {
+ return mPrivilegedAppAllowlist;
+ }
+
+ @NonNull
+ public ArrayMap<String, ArrayMap<String, Boolean>> getVendorPrivilegedAppAllowlist() {
+ return mVendorPrivilegedAppAllowlist;
+ }
+
+ @NonNull
+ public ArrayMap<String, ArrayMap<String, Boolean>> getProductPrivilegedAppAllowlist() {
+ return mProductPrivilegedAppAllowlist;
+ }
+
+ @NonNull
+ public ArrayMap<String, ArrayMap<String, Boolean>> getSystemExtPrivilegedAppAllowlist() {
+ return mSystemExtPrivilegedAppAllowlist;
+ }
+
+ @NonNull
+ public ArrayMap<String, ArrayMap<String, ArrayMap<String, Boolean>>>
+ getApexPrivilegedAppAllowlists() {
+ return mApexPrivilegedAppAllowlists;
+ }
+
+ @Nullable
+ public Boolean getOemAppAllowlistState(@NonNull String packageName,
+ @NonNull String permissionName) {
+ ArrayMap<String, Boolean> permissions = mOemAppAllowlist.get(packageName);
+ if (permissions == null) {
+ return null;
+ }
+ return permissions.get(permissionName);
+ }
+
+ @Nullable
+ public Boolean getPrivilegedAppAllowlistState(@NonNull String packageName,
+ @NonNull String permissionName) {
+ ArrayMap<String, Boolean> permissions = mPrivilegedAppAllowlist.get(packageName);
+ if (permissions == null) {
+ return null;
+ }
+ return permissions.get(permissionName);
+ }
+
+ @Nullable
+ public Boolean getVendorPrivilegedAppAllowlistState(@NonNull String packageName,
+ @NonNull String permissionName) {
+ ArrayMap<String, Boolean> permissions = mVendorPrivilegedAppAllowlist.get(packageName);
+ if (permissions == null) {
+ return null;
+ }
+ return permissions.get(permissionName);
+ }
+
+ @Nullable
+ public Boolean getProductPrivilegedAppAllowlistState(@NonNull String packageName,
+ @NonNull String permissionName) {
+ ArrayMap<String, Boolean> permissions = mProductPrivilegedAppAllowlist.get(packageName);
+ if (permissions == null) {
+ return null;
+ }
+ return permissions.get(permissionName);
+ }
+
+ @Nullable
+ public Boolean getSystemExtPrivilegedAppAllowlistState(@NonNull String packageName,
+ @NonNull String permissionName) {
+ ArrayMap<String, Boolean> permissions = mSystemExtPrivilegedAppAllowlist.get(packageName);
+ if (permissions == null) {
+ return null;
+ }
+ return permissions.get(permissionName);
+ }
+
+ @Nullable
+ public Boolean getApexPrivilegedAppAllowlistState(@NonNull String moduleName,
+ @NonNull String packageName, @NonNull String permissionName) {
+ ArrayMap<String, ArrayMap<String, Boolean>> allowlist =
+ mApexPrivilegedAppAllowlists.get(moduleName);
+ if (allowlist == null) {
+ return null;
+ }
+ ArrayMap<String, Boolean> permissions = allowlist.get(packageName);
+ if (permissions == null) {
+ return null;
+ }
+ return permissions.get(permissionName);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 2a2bcab56258..f9c0deb4c648 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -3314,13 +3314,10 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
final String permissionName = permission.getName();
final String containingApexPackageName =
mApexManager.getActiveApexPackageNameContainingPackage(packageName);
- if (isInSystemConfigPrivAppPermissions(pkg, permissionName,
- containingApexPackageName)) {
- return true;
- }
- if (isInSystemConfigPrivAppDenyPermissions(pkg, permissionName,
- containingApexPackageName)) {
- return false;
+ final Boolean allowlistState = getPrivilegedPermissionAllowlistState(pkg, permissionName,
+ containingApexPackageName);
+ if (allowlistState != null) {
+ return allowlistState;
}
// Updated system apps do not need to be allowlisted
if (packageSetting.getTransientState().isUpdatedSystemApp()) {
@@ -3356,61 +3353,43 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE;
}
- private boolean isInSystemConfigPrivAppPermissions(@NonNull AndroidPackage pkg,
- @NonNull String permission, String containingApexPackageName) {
- final SystemConfig systemConfig = SystemConfig.getInstance();
- final Set<String> permissions;
+ @Nullable
+ private Boolean getPrivilegedPermissionAllowlistState(@NonNull AndroidPackage pkg,
+ @NonNull String permissionName, String containingApexPackageName) {
+ final PermissionAllowlist permissionAllowlist =
+ SystemConfig.getInstance().getPermissionAllowlist();
+ final String packageName = pkg.getPackageName();
if (pkg.isVendor()) {
- permissions = systemConfig.getVendorPrivAppPermissions(pkg.getPackageName());
+ return permissionAllowlist.getVendorPrivilegedAppAllowlistState(packageName,
+ permissionName);
} else if (pkg.isProduct()) {
- permissions = systemConfig.getProductPrivAppPermissions(pkg.getPackageName());
+ return permissionAllowlist.getProductPrivilegedAppAllowlistState(packageName,
+ permissionName);
} else if (pkg.isSystemExt()) {
- permissions = systemConfig.getSystemExtPrivAppPermissions(pkg.getPackageName());
+ return permissionAllowlist.getSystemExtPrivilegedAppAllowlistState(packageName,
+ permissionName);
} else if (containingApexPackageName != null) {
- final String apexName = mApexManager.getApexModuleNameForPackageName(
- containingApexPackageName);
- final Set<String> privAppPermissions = systemConfig.getPrivAppPermissions(
- pkg.getPackageName());
- final Set<String> apexPermissions = systemConfig.getApexPrivAppPermissions(
- apexName, pkg.getPackageName());
- if (privAppPermissions != null) {
+ final Boolean nonApexAllowlistState =
+ permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName);
+ if (nonApexAllowlistState != null) {
// TODO(andreionea): Remove check as soon as all apk-in-apex
// permission allowlists are migrated.
Slog.w(TAG, "Package " + pkg.getPackageName() + " is an APK in APEX,"
+ " but has permission allowlist on the system image. Please bundle the"
+ " allowlist in the " + containingApexPackageName + " APEX instead.");
- if (apexPermissions != null) {
- permissions = new ArraySet<>(privAppPermissions);
- permissions.addAll(apexPermissions);
- } else {
- permissions = privAppPermissions;
- }
- } else {
- permissions = apexPermissions;
}
+ final String moduleName = mApexManager.getApexModuleNameForPackageName(
+ containingApexPackageName);
+ final Boolean apexAllowlistState =
+ permissionAllowlist.getApexPrivilegedAppAllowlistState(moduleName, packageName,
+ permissionName);
+ if (apexAllowlistState != null) {
+ return apexAllowlistState;
+ }
+ return nonApexAllowlistState;
} else {
- permissions = systemConfig.getPrivAppPermissions(pkg.getPackageName());
- }
- return CollectionUtils.contains(permissions, permission);
- }
-
- private boolean isInSystemConfigPrivAppDenyPermissions(@NonNull AndroidPackage pkg,
- @NonNull String permission, String containingApexPackageName) {
- final SystemConfig systemConfig = SystemConfig.getInstance();
- final Set<String> permissions;
- if (pkg.isVendor()) {
- permissions = systemConfig.getVendorPrivAppDenyPermissions(pkg.getPackageName());
- } else if (pkg.isProduct()) {
- permissions = systemConfig.getProductPrivAppDenyPermissions(pkg.getPackageName());
- } else if (pkg.isSystemExt()) {
- permissions = systemConfig.getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
- } else if (containingApexPackageName != null) {
- permissions = systemConfig.getApexPrivAppDenyPermissions(containingApexPackageName,
- pkg.getPackageName());
- } else {
- permissions = systemConfig.getPrivAppDenyPermissions(pkg.getPackageName());
+ return permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName);
}
- return CollectionUtils.contains(permissions, permission);
}
private boolean shouldGrantPermissionBySignature(@NonNull AndroidPackage pkg,
@@ -3612,8 +3591,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
return false;
}
// all oem permissions must explicitly be granted or denied
- final Boolean granted =
- SystemConfig.getInstance().getOemPermissions(pkg.getPackageName()).get(permission);
+ final Boolean granted = SystemConfig.getInstance().getPermissionAllowlist()
+ .getOemAppAllowlistState(pkg.getPackageName(), permission);
if (granted == null) {
throw new IllegalStateException("OEM permission " + permission
+ " requested by package " + pkg.getPackageName()
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 54ece7384f7a..983b7f463a1c 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -283,7 +283,7 @@ class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogIn
mItems.add(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
if (Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
+ Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserAdmin()) {
mItems.add(new BugReportAction());
}
} else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
@@ -535,9 +535,9 @@ class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogIn
}
}
- private boolean isCurrentUserOwner() {
+ private boolean isCurrentUserAdmin() {
UserInfo currentUser = getCurrentUser();
- return currentUser == null || currentUser.isPrimary();
+ return currentUser == null || currentUser.isAdmin();
}
private void addUsersToMenu(ArrayList<Action> items) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 399b94c0c921..d5fbe46c5582 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1054,6 +1054,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return;
}
+ // Make sure the device locks. Unfortunately, this has the side-effect of briefly revealing
+ // the lock screen before the dream appears. Note that this locking behavior needs to
+ // happen regardless of whether we end up dreaming (below) or not.
+ // TODO(b/261662912): Find a better way to lock the device that doesn't result in jank.
+ lockNow(null);
+
+ // Don't dream if the user isn't user zero.
+ // TODO(b/261907079): Move this check to DreamManagerService#canStartDreamingInternal().
+ if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
+ noDreamAction.run();
+ return;
+ }
+
final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
if (dreamManagerInternal == null || !dreamManagerInternal.canStartDreaming(isScreenOn)) {
noDreamAction.run();
@@ -2887,6 +2900,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
break;
+ case KeyEvent.KEYCODE_RECENT_APPS:
+ // TODO(b/261621522): Handle recents key presses
+ return key_consumed;
case KeyEvent.KEYCODE_APP_SWITCH:
if (!keyguardOn) {
if (down && repeatCount == 0) {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 1fe82f472937..09a7b29c18a2 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -25,7 +25,6 @@ import android.app.trust.TrustManager;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
-import android.content.IntentFilter;
import android.hardware.display.DisplayManagerInternal;
import android.media.AudioManager;
import android.media.Ringtone;
@@ -67,6 +66,7 @@ import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.PrintWriter;
+import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -140,9 +140,8 @@ public class Notifier {
private final NotifierHandler mHandler;
private final Executor mBackgroundExecutor;
private final Intent mScreenOnIntent;
- private final Bundle mScreenOnOptions;
private final Intent mScreenOffIntent;
- private final Bundle mScreenOffOptions;
+ private final Bundle mScreenOnOffOptions;
// True if the device should suspend when the screen is off due to proximity.
private final boolean mSuspendWhenScreenOffDueToProximityConfig;
@@ -204,14 +203,11 @@ public class Notifier {
mScreenOnIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- mScreenOnOptions = BroadcastOptions.makeRemovingMatchingFilter(
- new IntentFilter(Intent.ACTION_SCREEN_OFF)).toBundle();
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
mScreenOffIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- mScreenOffOptions = BroadcastOptions.makeRemovingMatchingFilter(
- new IntentFilter(Intent.ACTION_SCREEN_ON)).toBundle();
+ mScreenOnOffOptions = createScreenOnOffBroadcastOptions();
mSuspendWhenScreenOffDueToProximityConfig = context.getResources().getBoolean(
com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
@@ -229,6 +225,25 @@ public class Notifier {
}
/**
+ * Create the {@link BroadcastOptions} bundle that will be used with sending the
+ * {@link Intent#ACTION_SCREEN_ON} and {@link Intent#ACTION_SCREEN_OFF} broadcasts.
+ */
+ private Bundle createScreenOnOffBroadcastOptions() {
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ // This allows the broadcasting system to discard any older broadcasts
+ // waiting to be delivered to a process.
+ options.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
+ // Set namespace and key to identify which older broadcasts can be discarded.
+ // We could use any strings here but namespace needs to be unlikely to be reused with in
+ // the system_server process, as that could result in potentially discarding some
+ // non-screen on/off related broadcast.
+ options.setDeliveryGroupMatchingKey(
+ UUID.randomUUID().toString(),
+ Intent.ACTION_SCREEN_ON);
+ return options.toBundle();
+ }
+
+ /**
* Called when a wake lock is acquired.
*/
public void onWakeLockAcquired(int flags, String tag, String packageName,
@@ -798,7 +813,7 @@ public class Notifier {
if (mActivityManagerInternal.isSystemReady()) {
final boolean ordered = !mActivityManagerInternal.isModernQueueEnabled();
mActivityManagerInternal.broadcastIntent(mScreenOnIntent, mWakeUpBroadcastDone,
- null, ordered, UserHandle.USER_ALL, null, null, mScreenOnOptions);
+ null, ordered, UserHandle.USER_ALL, null, null, mScreenOnOffOptions);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
sendNextBroadcast();
@@ -823,7 +838,7 @@ public class Notifier {
if (mActivityManagerInternal.isSystemReady()) {
final boolean ordered = !mActivityManagerInternal.isModernQueueEnabled();
mActivityManagerInternal.broadcastIntent(mScreenOffIntent, mGoToSleepBroadcastDone,
- null, ordered, UserHandle.USER_ALL, null, null, mScreenOffOptions);
+ null, ordered, UserHandle.USER_ALL, null, null, mScreenOnOffOptions);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
sendNextBroadcast();
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index f3785885e4ec..6b2c6e30efe7 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -19,16 +19,18 @@ package com.android.server.power;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.thermal.IThermal;
+import android.hardware.thermal.IThermalChangedCallback;
+import android.hardware.thermal.TemperatureThreshold;
+import android.hardware.thermal.ThrottlingSeverity;
import android.hardware.thermal.V1_0.ThermalStatus;
import android.hardware.thermal.V1_0.ThermalStatusCode;
import android.hardware.thermal.V1_1.IThermalCallback;
-import android.hardware.thermal.V2_0.IThermalChangedCallback;
-import android.hardware.thermal.V2_0.TemperatureThreshold;
-import android.hardware.thermal.V2_0.ThrottlingSeverity;
import android.os.Binder;
import android.os.CoolingDevice;
import android.os.Handler;
import android.os.HwBinder;
+import android.os.IBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.IThermalStatusListener;
@@ -37,6 +39,7 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemClock;
@@ -56,12 +59,14 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
/**
* This is a system service that listens to HAL thermal events and dispatch those to listeners.
@@ -98,7 +103,7 @@ public class ThermalManagerService extends SystemService {
@GuardedBy("mLock")
private int mStatus;
- /** If override status takes effect*/
+ /** If override status takes effect */
@GuardedBy("mLock")
private boolean mIsStatusOverride;
@@ -144,6 +149,10 @@ public class ThermalManagerService extends SystemService {
// Connect to HAL and post to listeners.
boolean halConnected = (mHalWrapper != null);
if (!halConnected) {
+ mHalWrapper = new ThermalHalAidlWrapper();
+ halConnected = mHalWrapper.connectToHal();
+ }
+ if (!halConnected) {
mHalWrapper = new ThermalHal20Wrapper();
halConnected = mHalWrapper.connectToHal();
}
@@ -684,6 +693,162 @@ public class ThermalManagerService extends SystemService {
}
}
+ @VisibleForTesting
+ static class ThermalHalAidlWrapper extends ThermalHalWrapper implements IBinder.DeathRecipient {
+ /* Proxy object for the Thermal HAL AIDL service. */
+ private IThermal mInstance = null;
+
+ /** Callback for Thermal HAL AIDL. */
+ private final IThermalChangedCallback mThermalChangedCallback =
+ new IThermalChangedCallback.Stub() {
+ @Override public void notifyThrottling(
+ android.hardware.thermal.Temperature temperature)
+ throws RemoteException {
+ Temperature svcTemperature = new Temperature(temperature.value,
+ temperature.type, temperature.name, temperature.throttlingStatus);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.onValues(svcTemperature);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override public int getInterfaceVersion() throws RemoteException {
+ return this.VERSION;
+ }
+
+ @Override public String getInterfaceHash() throws RemoteException {
+ return this.HASH;
+ }
+ };
+
+ @Override
+ protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ final List<Temperature> ret = new ArrayList<>();
+ if (mInstance == null) {
+ return ret;
+ }
+ try {
+ final android.hardware.thermal.Temperature[] halRet =
+ shouldFilter ? mInstance.getTemperaturesWithType(type)
+ : mInstance.getTemperatures();
+ for (android.hardware.thermal.Temperature t : halRet) {
+ if (!Temperature.isValidStatus(t.throttlingStatus)) {
+ Slog.e(TAG, "Invalid temperature status " + t.throttlingStatus
+ + " received from AIDL HAL");
+ t.throttlingStatus = Temperature.THROTTLING_NONE;
+ }
+ if (shouldFilter && t.type != type) {
+ continue;
+ }
+ ret.add(new Temperature(t.value, t.type, t.name, t.throttlingStatus));
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
+ protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ final List<CoolingDevice> ret = new ArrayList<>();
+ if (mInstance == null) {
+ return ret;
+ }
+ try {
+ final android.hardware.thermal.CoolingDevice[] halRet = shouldFilter
+ ? mInstance.getCoolingDevicesWithType(type)
+ : mInstance.getCoolingDevices();
+ for (android.hardware.thermal.CoolingDevice t : halRet) {
+ if (!CoolingDevice.isValidType(t.type)) {
+ Slog.e(TAG, "Invalid cooling device type " + t.type + " from AIDL HAL");
+ continue;
+ }
+ if (shouldFilter && t.type != type) {
+ continue;
+ }
+ ret.add(new CoolingDevice(t.value, t.type, t.name));
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
+ @NonNull protected List<TemperatureThreshold> getTemperatureThresholds(
+ boolean shouldFilter, int type) {
+ synchronized (mHalLock) {
+ final List<TemperatureThreshold> ret = new ArrayList<>();
+ if (mInstance == null) {
+ return ret;
+ }
+ try {
+ final TemperatureThreshold[] halRet =
+ shouldFilter ? mInstance.getTemperatureThresholdsWithType(type)
+ : mInstance.getTemperatureThresholds();
+
+ return Arrays.stream(halRet).filter(t -> t.type == type).collect(
+ Collectors.toList());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getTemperatureThresholds, reconnecting...", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
+ protected boolean connectToHal() {
+ synchronized (mHalLock) {
+ IBinder binder = Binder.allowBlocking(ServiceManager.waitForDeclaredService(
+ IThermal.DESCRIPTOR + "/default"));
+ initProxyAndRegisterCallback(binder);
+ }
+ return mInstance != null;
+ }
+
+ @VisibleForTesting
+ void initProxyAndRegisterCallback(IBinder binder) {
+ synchronized (mHalLock) {
+ if (binder != null) {
+ mInstance = IThermal.Stub.asInterface(binder);
+ try {
+ binder.linkToDeath(this, 0);
+ mInstance.registerThermalChangedCallback(mThermalChangedCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to connect IThermal AIDL instance", e);
+ mInstance = null;
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void dump(PrintWriter pw, String prefix) {
+ synchronized (mHalLock) {
+ pw.print(prefix);
+ pw.println(
+ "ThermalHAL AIDL " + IThermal.VERSION + " connected: " + (mInstance != null
+ ? "yes" : "no"));
+ }
+ }
+
+ @Override
+ public synchronized void binderDied() {
+ Slog.w(TAG, "IThermal HAL instance died");
+ mInstance = null;
+ }
+ }
static class ThermalHal10Wrapper extends ThermalHalWrapper {
/** Proxy object for the Thermal HAL 1.0 service. */
@@ -814,8 +979,8 @@ public class ThermalManagerService extends SystemService {
android.hardware.thermal.V1_0.Temperature temperature) {
Temperature thermalSvcTemp = new Temperature(
temperature.currentValue, temperature.type, temperature.name,
- isThrottling ? ThrottlingSeverity.SEVERE
- : ThrottlingSeverity.NONE);
+ isThrottling ? Temperature.THROTTLING_SEVERE
+ : Temperature.THROTTLING_NONE);
final long token = Binder.clearCallingIdentity();
try {
mCallback.onValues(thermalSvcTemp);
@@ -941,8 +1106,9 @@ public class ThermalManagerService extends SystemService {
private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null;
/** HWbinder callback for Thermal HAL 2.0. */
- private final IThermalChangedCallback.Stub mThermalCallback20 =
- new IThermalChangedCallback.Stub() {
+ private final android.hardware.thermal.V2_0.IThermalChangedCallback.Stub
+ mThermalCallback20 =
+ new android.hardware.thermal.V2_0.IThermalChangedCallback.Stub() {
@Override
public void notifyThrottling(
android.hardware.thermal.V2_0.Temperature temperature) {
@@ -976,7 +1142,7 @@ public class ThermalManagerService extends SystemService {
temperature.throttlingStatus)) {
Slog.e(TAG, "Invalid status data from HAL");
temperature.throttlingStatus =
- Temperature.THROTTLING_NONE;
+ Temperature.THROTTLING_NONE;
}
ret.add(new Temperature(
temperature.value, temperature.type,
@@ -1043,7 +1209,9 @@ public class ThermalManagerService extends SystemService {
mThermalHal20.getTemperatureThresholds(shouldFilter, type,
(status, thresholds) -> {
if (ThermalStatusCode.SUCCESS == status.code) {
- ret.addAll(thresholds);
+ ret.addAll(thresholds.stream().map(
+ this::convertToAidlTemperatureThreshold).collect(
+ Collectors.toList()));
} else {
Slog.e(TAG,
"Couldn't get temperature thresholds because of HAL "
@@ -1057,6 +1225,16 @@ public class ThermalManagerService extends SystemService {
}
}
+ private TemperatureThreshold convertToAidlTemperatureThreshold(
+ android.hardware.thermal.V2_0.TemperatureThreshold threshold) {
+ final TemperatureThreshold ret = new TemperatureThreshold();
+ ret.name = threshold.name;
+ ret.type = threshold.type;
+ ret.coldThrottlingThresholds = threshold.coldThrottlingThresholds;
+ ret.hotThrottlingThresholds = threshold.hotThrottlingThresholds;
+ return ret;
+ }
+
@Override
protected boolean connectToHal() {
synchronized (mHalLock) {
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index ab35dc86b961..6d391779ea18 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -223,7 +223,7 @@ public final class SensorPrivacyService extends SystemService {
}
class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements
- AppOpsManager.OnOpNotedListener, AppOpsManager.OnOpStartedListener,
+ AppOpsManager.OnOpNotedInternalListener, AppOpsManager.OnOpStartedListener,
IBinder.DeathRecipient, UserManagerInternal.UserRestrictionsListener {
private final SensorPrivacyHandler mHandler;
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index c379abc72dc0..6c616e0584df 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2408,7 +2408,20 @@ public class StatsPullAtomService extends SystemService {
metrics.gpuTotalUsageKb,
metrics.gpuPrivateAllocationsKb,
metrics.dmaBufTotalExportedKb,
- metrics.shmemKb));
+ metrics.shmemKb,
+ metrics.totalKb,
+ metrics.freeKb,
+ metrics.availableKb,
+ metrics.activeKb,
+ metrics.inactiveKb,
+ metrics.activeAnonKb,
+ metrics.inactiveAnonKb,
+ metrics.activeFileKb,
+ metrics.inactiveFileKb,
+ metrics.swapTotalKb,
+ metrics.swapFreeKb,
+ metrics.cmaTotalKb,
+ metrics.cmaFreeKb));
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
index 9ebf59ef8363..2ab4fdf77232 100644
--- a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -83,6 +83,19 @@ final class SystemMemoryUtil {
result.pageTablesKb = (int) mInfos[Debug.MEMINFO_PAGE_TABLES];
result.kernelStackKb = (int) mInfos[Debug.MEMINFO_KERNEL_STACK];
result.shmemKb = (int) mInfos[Debug.MEMINFO_SHMEM];
+ result.totalKb = (int) mInfos[Debug.MEMINFO_TOTAL];
+ result.freeKb = (int) mInfos[Debug.MEMINFO_FREE];
+ result.availableKb = (int) mInfos[Debug.MEMINFO_AVAILABLE];
+ result.activeKb = (int) mInfos[Debug.MEMINFO_ACTIVE];
+ result.inactiveKb = (int) mInfos[Debug.MEMINFO_INACTIVE];
+ result.activeAnonKb = (int) mInfos[Debug.MEMINFO_ACTIVE_ANON];
+ result.inactiveAnonKb = (int) mInfos[Debug.MEMINFO_INACTIVE_ANON];
+ result.activeFileKb = (int) mInfos[Debug.MEMINFO_ACTIVE_FILE];
+ result.inactiveFileKb = (int) mInfos[Debug.MEMINFO_INACTIVE_FILE];
+ result.swapTotalKb = (int) mInfos[Debug.MEMINFO_SWAP_TOTAL];
+ result.swapFreeKb = (int) mInfos[Debug.MEMINFO_SWAP_FREE];
+ result.cmaTotalKb = (int) mInfos[Debug.MEMINFO_CMA_TOTAL];
+ result.cmaFreeKb = (int) mInfos[Debug.MEMINFO_CMA_FREE];
result.totalIonKb = totalIonKb;
result.gpuTotalUsageKb = gpuTotalUsageKb;
result.gpuPrivateAllocationsKb = gpuPrivateAllocationsKb;
@@ -97,6 +110,19 @@ final class SystemMemoryUtil {
public int pageTablesKb;
public int kernelStackKb;
public int shmemKb;
+ public int totalKb;
+ public int freeKb;
+ public int availableKb;
+ public int activeKb;
+ public int inactiveKb;
+ public int activeAnonKb;
+ public int inactiveAnonKb;
+ public int activeFileKb;
+ public int inactiveFileKb;
+ public int swapTotalKb;
+ public int swapFreeKb;
+ public int cmaTotalKb;
+ public int cmaFreeKb;
public int totalIonKb;
public int gpuTotalUsageKb;
public int gpuPrivateAllocationsKb;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9245d7ff4728..f725d1a11243 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -513,7 +513,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// dies. After an activity is launched it follows the value
// of #mIcicle.
boolean launchFailed; // set if a launched failed, to abort on 2nd try
- boolean stopped; // is activity pause finished?
boolean delayedResume; // not yet resumed because of stopped app switches?
boolean finishing; // activity in pending finish list?
boolean deferRelaunchUntilPaused; // relaunch of activity is being deferred until pause is
@@ -875,6 +874,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean mOverrideTaskTransition;
boolean mDismissKeyguard;
+ /** True if the activity has reported stopped; False if the activity becomes visible. */
boolean mAppStopped;
// A hint to override the window specified rotation animation, or -1 to use the window specified
// value. We use this so that we can select the right animation in the cases of starting
@@ -1135,7 +1135,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.print(prefix); pw.print("mHaveState="); pw.print(mHaveState);
pw.print(" mIcicle="); pw.println(mIcicle);
pw.print(prefix); pw.print("state="); pw.print(mState);
- pw.print(" stopped="); pw.print(stopped);
pw.print(" delayedResume="); pw.print(delayedResume);
pw.print(" finishing="); pw.println(finishing);
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
@@ -2021,7 +2020,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
requestCode = _reqCode;
setState(INITIALIZING, "ActivityRecord ctor");
launchFailed = false;
- stopped = false;
delayedResume = false;
finishing = false;
deferRelaunchUntilPaused = false;
@@ -3871,7 +3869,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
taskFragment.sendTaskFragmentInfoChanged();
}
- if (stopped) {
+ if (mAppStopped) {
abortAndClearOptionsAnimation();
}
}
@@ -5707,11 +5705,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- void notifyAppResumed(boolean wasStopped) {
+ void notifyAppResumed() {
if (getParent() == null) {
Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
return;
}
+ final boolean wasStopped = mAppStopped;
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s",
wasStopped, this);
mAppStopped = false;
@@ -5726,32 +5725,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Notify that the app has stopped, and it is okay to destroy any surfaces which were
- * keeping alive in case they were still being used.
- */
- void notifyAppStopped() {
- ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
- mAppStopped = true;
- firstWindowDrawn = false;
- // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
- // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
- // Clear any surface transactions and content overlay in this case.
- if (task != null && task.mLastRecentsAnimationTransaction != null) {
- task.clearLastRecentsAnimationTransaction(true /* forceRemoveOverlay */);
- }
- // Reset the last saved PiP snap fraction on app stop.
- mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
- mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
- if (isClientVisible()) {
- // Though this is usually unlikely to happen, still make sure the client is invisible.
- setClientVisible(false);
- }
- destroySurfaces();
- // Remove any starting window that was added for this app if they are still around.
- removeStartingWindow();
- }
-
- /**
* Suppress transition until the new activity becomes ready, otherwise the keyguard can appear
* for a short amount of time before the new process with the new activity had the ability to
* set its showWhenLocked flags.
@@ -6111,7 +6084,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLastNewIntent = newIntents.get(newIntents.size() - 1);
}
newIntents = null;
- stopped = false;
if (isActivityTypeHome()) {
mTaskSupervisor.updateHomeProcess(task.getBottomMostActivity().app);
@@ -6233,7 +6205,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
resumeKeyDispatchingLocked();
try {
- stopped = false;
ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);
setState(STOPPING, "stopIfPossible");
@@ -6251,7 +6222,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// notification will clean things up.
Slog.w(TAG, "Exception thrown during pause", e);
// Just in case, assume it to be stopped.
- stopped = true;
+ mAppStopped = true;
ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this);
setState(STOPPED, "stopIfPossible");
if (deferRelaunchUntilPaused) {
@@ -6260,12 +6231,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ /**
+ * Notifies that the activity has stopped, and it is okay to destroy any surfaces which were
+ * keeping alive in case they were still being used.
+ */
void activityStopped(Bundle newIcicle, PersistableBundle newPersistentState,
CharSequence description) {
+ removeStopTimeout();
final boolean isStopping = mState == STOPPING;
if (!isStopping && mState != RESTARTING_PROCESS) {
Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this + " " + mState);
- removeStopTimeout();
return;
}
if (newPersistentState != null) {
@@ -6281,28 +6256,42 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
updateTaskDescription(description);
}
ProtoLog.i(WM_DEBUG_STATES, "Saving icicle of %s: %s", this, mIcicle);
- if (!stopped) {
+
+ if (isStopping) {
ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPED: %s (stop complete)", this);
- removeStopTimeout();
- stopped = true;
- if (isStopping) {
- setState(STOPPED, "activityStoppedLocked");
- }
+ setState(STOPPED, "activityStopped");
+ }
- notifyAppStopped();
+ mAppStopped = true;
+ firstWindowDrawn = false;
+ // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
+ // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
+ // Clear any surface transactions and content overlay in this case.
+ if (task.mLastRecentsAnimationTransaction != null) {
+ task.clearLastRecentsAnimationTransaction(true /* forceRemoveOverlay */);
+ }
+ // Reset the last saved PiP snap fraction on app stop.
+ mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
+ mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
+ if (isClientVisible()) {
+ // Though this is usually unlikely to happen, still make sure the client is invisible.
+ setClientVisible(false);
+ }
+ destroySurfaces();
+ // Remove any starting window that was added for this app if they are still around.
+ removeStartingWindow();
- if (finishing) {
- abortAndClearOptionsAnimation();
+ if (finishing) {
+ abortAndClearOptionsAnimation();
+ } else {
+ if (deferRelaunchUntilPaused) {
+ destroyImmediately("stop-config");
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
} else {
- if (deferRelaunchUntilPaused) {
- destroyImmediately("stop-config");
- mRootWindowContainer.resumeFocusedTasksTopActivities();
- } else {
- mAtmService.updatePreviousProcess(this);
- }
+ mAtmService.updatePreviousProcess(this);
}
- mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
}
+ mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
}
void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {
@@ -6840,7 +6829,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private ActivityRecord getWaitingHistoryRecordLocked() {
// First find the real culprit... if this activity has stopped, then the key dispatching
// timeout should not be caused by this.
- if (stopped) {
+ if (mAppStopped) {
final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (rootTask == null) {
return this;
@@ -6921,7 +6910,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
if (isState(RESUMED) || getRootTask() == null
|| this == getTaskFragment().getPausingActivity()
- || !mHaveState || !stopped) {
+ || !mHaveState || !mAppStopped) {
// We're not ready for this kind of thing.
return false;
}
@@ -7683,6 +7672,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// This activity may relaunch or perform configuration change so once it has reported drawn,
// the screen can be unfrozen.
ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS);
+ if (mTransitionController.isCollecting(this)) {
+ // In case the task was changed from PiP but still keeps old transform.
+ task.resetSurfaceControlTransforms();
+ }
}
void setRequestedOrientation(int requestedOrientation) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1e063754c8c3..2f4d154503d1 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2285,6 +2285,15 @@ class ActivityStarter {
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
+ if (r.info.requiredDisplayCategory != null && mSourceRecord != null
+ && !r.info.requiredDisplayCategory.equals(
+ mSourceRecord.info.requiredDisplayCategory)) {
+ // Adding NEW_TASK flag for activity with display category attribute if the display
+ // category of the source record is different, so that the activity won't be launched
+ // in source record's task.
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ }
+
sendNewTaskResultRequestIfNeeded();
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
@@ -2372,6 +2381,12 @@ class ActivityStarter {
Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
mInTask = null;
}
+ // Prevent to start activity in Task with different display category
+ if (mInTask != null && !mInTask.isSameRequiredDisplayCategory(r.info)) {
+ Slog.w(TAG, "Starting activity in task with different display category: "
+ + mInTask);
+ mInTask = null;
+ }
mInTaskFragment = inTaskFragment;
mStartFlags = startFlags;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index eb04687d7d0c..866fef76f3ca 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3616,19 +3616,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void setSplitScreenResizing(boolean resizing) {
- enforceTaskPermission("setSplitScreenResizing()");
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- mTaskSupervisor.setSplitScreenResizing(resizing);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
public IWindowOrganizerController getWindowOrganizerController() {
return mWindowOrganizerController;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 8a247cf8b4d3..034089b19aa0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -207,9 +207,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// Used to indicate that a task is removed it should also be removed from recents.
static final boolean REMOVE_FROM_RECENTS = true;
- /** True if the docked root task is currently being resized. */
- private boolean mDockedRootTaskResizing;
-
// Activity actions an app cannot start if it uses a permission which is not granted.
private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
new ArrayMap<>();
@@ -1528,15 +1525,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
return mLaunchParamsController;
}
- void setSplitScreenResizing(boolean resizing) {
- if (resizing == mDockedRootTaskResizing) {
- return;
- }
-
- mDockedRootTaskResizing = resizing;
- mWindowManager.setDockedRootTaskResizing(resizing);
- }
-
private void removePinnedRootTaskInSurfaceTransaction(Task rootTask) {
/**
* Workaround: Force-stop all the activities in the root pinned task before we reparent them
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d5802cf37bad..169e7703b1ee 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -525,7 +525,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
- final DockedTaskDividerController mDividerControllerLocked;
final PinnedTaskController mPinnedTaskController;
final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
@@ -1163,7 +1162,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mDisplayPolicy.systemReady();
}
mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
- mDividerControllerLocked = new DockedTaskDividerController(this);
mPinnedTaskController = new PinnedTaskController(mWmService, this);
final Transaction pendingTransaction = getPendingTransaction();
@@ -2594,10 +2592,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- DockedTaskDividerController getDockedDividerController() {
- return mDividerControllerLocked;
- }
-
PinnedTaskController getPinnedTaskController() {
return mPinnedTaskController;
}
@@ -3392,6 +3386,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!controller.isCollecting(this)) {
controller.collect(this);
startAsyncRotationIfNeeded();
+ if (mFixedRotationLaunchingApp != null) {
+ setSeamlessTransitionForFixedRotation(controller.getCollectingTransition());
+ }
}
return;
}
@@ -3401,12 +3398,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
if (mFixedRotationLaunchingApp != null) {
// A fixed-rotation transition is done, then continue to start a seamless display
- // transition. And be fore the start transaction is applied, the non-app windows
- // need to keep in previous rotation to avoid showing inconsistent content.
- t.setSeamlessRotation(this);
- if (mAsyncRotationController != null) {
- mAsyncRotationController.keepAppearanceInPreviousRotation();
- }
+ // transition.
+ setSeamlessTransitionForFixedRotation(t);
} else if (isRotationChanging()) {
if (displayChange != null) {
final boolean seamless = mDisplayRotation.shouldRotateSeamlessly(
@@ -3425,6 +3418,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
+ private void setSeamlessTransitionForFixedRotation(Transition t) {
+ t.setSeamlessRotation(this);
+ // Before the start transaction is applied, the non-app windows need to keep in previous
+ // rotation to avoid showing inconsistent content.
+ if (mAsyncRotationController != null) {
+ mAsyncRotationController.keepAppearanceInPreviousRotation();
+ }
+ }
+
/** If the display is in transition, there should be a screenshot covering it. */
@Override
boolean inTransition() {
diff --git a/services/core/java/com/android/server/wm/DockedTaskDividerController.java b/services/core/java/com/android/server/wm/DockedTaskDividerController.java
deleted file mode 100644
index 925a6d858a3d..000000000000
--- a/services/core/java/com/android/server/wm/DockedTaskDividerController.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-
-/**
- * Keeps information about the docked task divider.
- */
-public class DockedTaskDividerController {
-
- private final DisplayContent mDisplayContent;
- private boolean mResizing;
-
- private final Rect mTouchRegion = new Rect();
-
- DockedTaskDividerController(DisplayContent displayContent) {
- mDisplayContent = displayContent;
- }
-
- boolean isResizing() {
- return mResizing;
- }
-
- void setResizing(boolean resizing) {
- if (mResizing != resizing) {
- mResizing = resizing;
- resetDragResizingChangeReported();
- }
- }
-
- void setTouchRegion(Rect touchRegion) {
- mTouchRegion.set(touchRegion);
- // We need to report touchable region changes to accessibility.
- if (mDisplayContent.mWmService.mAccessibilityController.hasCallbacks()) {
- mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(
- mDisplayContent.getDisplayId());
- }
- }
-
- void getTouchRegion(Rect outRegion) {
- outRegion.set(mTouchRegion);
- }
-
- private void resetDragResizingChangeReported() {
- mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
- true /* traverseTopToBottom */);
- }
-}
diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java
deleted file mode 100644
index 684cf06e08b8..000000000000
--- a/services/core/java/com/android/server/wm/DragResizeMode.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
-/**
- * Describes the mode in which a window is drag resizing.
- */
-class DragResizeMode {
-
- /**
- * Freeform mode: Client surface is fullscreen, and client is responsible to draw window at
- * the correct position.
- */
- static final int DRAG_RESIZE_MODE_FREEFORM = 0;
-
- /**
- * Mode for resizing the docked (and adjacent) root task: Client surface is fullscreen, but
- * window is drawn at (0, 0), window manager is responsible for positioning the surface when
- * dragging.
- */
- static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
-
- static boolean isModeAllowedForRootTask(Task rootTask, int mode) {
- switch (mode) {
- case DRAG_RESIZE_MODE_FREEFORM:
- return rootTask.getWindowingMode() == WINDOWING_MODE_FREEFORM;
- default:
- return false;
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4c7f6fe7a8b4..749fa1f6610b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -418,7 +418,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
} else if (!isDocument && !taskIsDocument
&& mIdealRecord == null && mCandidateRecord == null
&& task.rootAffinity != null) {
- if (task.rootAffinity.equals(mTaskAffinity)) {
+ if (task.rootAffinity.equals(mTaskAffinity)
+ && task.isSameRequiredDisplayCategory(mInfo)) {
ProtoLog.d(WM_DEBUG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate root tasks. We save off this candidate, but keep
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 116096249b86..36747c8fbdc1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -466,7 +466,6 @@ class Task extends TaskFragment {
// Whether the task is currently being drag-resized
private boolean mDragResizing;
- private int mDragResizeMode;
// This represents the last resolved activity values for this task
// NOTE: This value needs to be persisted with each task
@@ -491,6 +490,9 @@ class Task extends TaskFragment {
private int mForceHiddenFlags = 0;
private boolean mForceTranslucent = false;
+ // The display category name for this task.
+ String mRequiredDisplayCategory;
+
// TODO(b/160201781): Revisit double invocation issue in Task#removeChild.
/**
* Skip {@link ActivityTaskSupervisor#removeTask(Task, boolean, boolean, String)} execution if
@@ -1011,6 +1013,7 @@ class Task extends TaskFragment {
// affinity -- we don't want it changing after initially set, but the initially
// set value may be null.
rootAffinity = affinity;
+ mRequiredDisplayCategory = info.requiredDisplayCategory;
}
effectiveUid = info.applicationInfo.uid;
mIsEffectivelySystemApp = info.applicationInfo.isSystemApp();
@@ -1121,11 +1124,12 @@ class Task extends TaskFragment {
if (inMultiWindowMode() || !hasChild()) return false;
if (intent != null) {
final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
+ if ((intent.getFlags() & returnHomeFlags) != returnHomeFlags) {
+ return false;
+ }
final Task task = getDisplayArea() != null ? getDisplayArea().getRootHomeTask() : null;
- final boolean isLockTaskModeViolation = task != null
- && mAtmService.getLockTaskController().isLockTaskModeViolation(task);
- return (intent.getFlags() & returnHomeFlags) == returnHomeFlags
- && !isLockTaskModeViolation;
+ return !(task != null
+ && mAtmService.getLockTaskController().isLockTaskModeViolation(task));
}
final Task bottomTask = getBottomMostTask();
return bottomTask != this && bottomTask.returnsToHomeRootTask();
@@ -2802,11 +2806,6 @@ class Task extends TaskFragment {
}
final Task rootTask = getRootTask();
- final DisplayContent displayContent = rootTask.getDisplayContent();
- // It doesn't matter if we in particular are part of the resize, since we couldn't have
- // a DimLayer anyway if we weren't visible.
- final boolean dockedResizing = displayContent != null
- && displayContent.mDividerControllerLocked.isResizing();
if (inFreeformWindowingMode()) {
boolean[] foundTop = { false };
forAllActivities(a -> { getMaxVisibleBounds(a, out, foundTop); });
@@ -2817,18 +2816,10 @@ class Task extends TaskFragment {
if (!matchParentBounds()) {
// When minimizing the root docked task when going home, we don't adjust the task bounds
- // so we need to intersect the task bounds with the root task bounds here.
- //
- // If we are Docked Resizing with snap points, the task bounds could be smaller than the
- // root task bounds and so we don't even want to use them. Even if the app should not be
- // resized the Dim should keep up with the divider.
- if (dockedResizing) {
- rootTask.getBounds(out);
- } else {
- rootTask.getBounds(mTmpRect);
- mTmpRect.intersect(getBounds());
- out.set(mTmpRect);
- }
+ // so we need to intersect the task bounds with the root task bounds here..
+ rootTask.getBounds(mTmpRect);
+ mTmpRect.intersect(getBounds());
+ out.set(mTmpRect);
} else {
out.set(getBounds());
}
@@ -2859,16 +2850,15 @@ class Task extends TaskFragment {
}
}
- void setDragResizing(boolean dragResizing, int dragResizeMode) {
+ void setDragResizing(boolean dragResizing) {
if (mDragResizing != dragResizing) {
- // No need to check if the mode is allowed if it's leaving dragResize
+ // No need to check if allowed if it's leaving dragResize
if (dragResizing
- && !DragResizeMode.isModeAllowedForRootTask(getRootTask(), dragResizeMode)) {
- throw new IllegalArgumentException("Drag resize mode not allow for root task id="
- + getRootTaskId() + " dragResizeMode=" + dragResizeMode);
+ && !(getRootTask().getWindowingMode() == WINDOWING_MODE_FREEFORM)) {
+ throw new IllegalArgumentException("Drag resize not allow for root task id="
+ + getRootTaskId());
}
mDragResizing = dragResizing;
- mDragResizeMode = dragResizeMode;
resetDragResizingChangeReported();
}
}
@@ -2877,10 +2867,6 @@ class Task extends TaskFragment {
return mDragResizing;
}
- int getDragResizeMode() {
- return mDragResizeMode;
- }
-
void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
if (displayContent == null) {
return;
@@ -6078,6 +6064,15 @@ class Task extends TaskFragment {
}
}
+ /**
+ * Return true if the activityInfo has the same requiredDisplayCategory as this task.
+ */
+ boolean isSameRequiredDisplayCategory(@NonNull ActivityInfo info) {
+ return mRequiredDisplayCategory != null && mRequiredDisplayCategory.equals(
+ info.requiredDisplayCategory)
+ || (mRequiredDisplayCategory == null && info.requiredDisplayCategory == null);
+ }
+
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3f2f02be5f8a..9126586bafd9 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1361,7 +1361,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (next.attachedToProcess()) {
if (DEBUG_SWITCH) {
- Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.stopped
+ Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.mAppStopped
+ " visibleRequested=" + next.isVisibleRequested());
}
@@ -1376,7 +1376,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|| mLastPausedActivity != null && !mLastPausedActivity.occludesParent();
// This activity is now becoming visible.
- if (!next.isVisibleRequested() || next.stopped || lastActivityTranslucent) {
+ if (!next.isVisibleRequested() || next.mAppStopped || lastActivityTranslucent) {
next.app.addToPendingTop();
next.setVisibility(true);
}
@@ -1427,7 +1427,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// Do over!
mTaskSupervisor.scheduleResumeTopActivities();
}
- if (!next.isVisibleRequested() || next.stopped) {
+ if (!next.isVisibleRequested() || next.mAppStopped) {
next.setVisibility(true);
}
next.completeResumeLocked();
@@ -1456,7 +1456,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// Well the app will no longer be stopped.
// Clear app token stopped state in window manager if needed.
- next.notifyAppResumed(next.stopped);
+ next.notifyAppResumed();
EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
next.getTask().mTaskId, next.shortComponentName);
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 5b32149b818d..9b3fb6b881c4 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -27,7 +27,6 @@ import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -368,7 +367,7 @@ class TaskPositioner implements IBinder.DeathRecipient {
private void endDragLocked() {
mResizing = false;
- mTask.setDragResizing(false, DRAG_RESIZE_MODE_FREEFORM);
+ mTask.setDragResizing(false);
}
/** Returns true if the move operation should be ended. */
@@ -380,7 +379,7 @@ class TaskPositioner implements IBinder.DeathRecipient {
if (mCtrlType != CTRL_NONE) {
resizeDrag(x, y);
- mTask.setDragResizing(true, DRAG_RESIZE_MODE_FREEFORM);
+ mTask.setDragResizing(true);
return false;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0c2cc4380bb2..1d17cd43384a 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1032,10 +1032,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @param dc The display this container is on after changes.
*/
void onDisplayChanged(DisplayContent dc) {
- if (mDisplayContent != null) {
+ if (mDisplayContent != null && mDisplayContent != dc) {
+ // Cancel any change transition queued-up for this container on the old display when
+ // this container is moved from the old display.
mDisplayContent.mClosingChangingContainers.remove(this);
if (mDisplayContent.mChangingContainers.remove(this)) {
- // Cancel any change transition queued-up for this container on the old display.
mSurfaceFreezer.unfreeze(getSyncTransaction());
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f6f825f42add..23bce36fc5d4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -168,7 +168,6 @@ import android.app.IActivityManager;
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -178,7 +177,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.TestUtilityService;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -3718,19 +3716,9 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- try {
- // TODO(b/221898546): remove the following and convert to jni
- IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlingerAIDL");
- if (surfaceFlinger != null) {
- ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
- Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.gui.ISurfaceComposer");
- surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
- data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
+ if (!SurfaceControl.bootFinished()) {
+ ProtoLog.w(WM_ERROR, "performEnableScreen: bootFinished() failed.");
+ return;
}
EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());
@@ -7140,20 +7128,6 @@ public class WindowManagerService extends IWindowManager.Stub
return 0;
}
- void setDockedRootTaskResizing(boolean resizing) {
- getDefaultDisplayContentLocked().getDockedDividerController().setResizing(resizing);
- requestTraversal();
- }
-
- @Override
- public void setDockedTaskDividerTouchRegion(Rect touchRegion) {
- synchronized (mGlobalLock) {
- final DisplayContent dc = getDefaultDisplayContentLocked();
- dc.getDockedDividerController().setTouchRegion(touchRegion);
- dc.updateTouchExcludeRegion();
- }
- }
-
void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
synchronized (mGlobalLock) {
mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 72411727361a..9b69369d8195 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -51,7 +51,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
@@ -722,7 +721,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING) != 0) {
- tr.setDragResizing(c.getDragResizing(), DRAG_RESIZE_MODE_FREEFORM);
+ tr.setDragResizing(c.getDragResizing());
}
final int childWindowingMode = c.getActivityWindowingMode();
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index d2cd8f8e8b0b..e9b81ec03081 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -903,7 +903,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
if (launchedActivity == activity) {
continue;
}
- if (!activity.stopped) {
+ if (!activity.mAppStopped) {
return true;
}
}
@@ -926,7 +926,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
boolean shouldKillProcessForRemovedTask(Task task) {
for (int k = 0; k < mActivities.size(); k++) {
final ActivityRecord activity = mActivities.get(k);
- if (!activity.stopped) {
+ if (!activity.mAppStopped) {
// Don't kill process(es) that has an activity not stopped.
return false;
}
@@ -956,7 +956,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
// Don't consider any activities that are currently not in a state where they
// can be destroyed.
- if (r.isVisibleRequested() || !r.stopped || !r.hasSavedState() || !r.isDestroyable()
+ if (r.isVisibleRequested() || !r.mAppStopped || !r.hasSavedState() || !r.isDestroyable()
|| r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
continue;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1b7bd9e1f36f..4d6f7bc5011e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -36,9 +36,6 @@ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
-import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
-import static android.view.WindowCallbacks.RESIZE_MODE_INVALID;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
@@ -123,8 +120,6 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE
import static com.android.server.wm.AnimationSpecProto.MOVE;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -370,7 +365,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
boolean mHidden = true; // Used to determine if to show child windows.
private boolean mDragResizing;
private boolean mDragResizingChangeReported = true;
- private int mResizeMode;
private boolean mRedrawForSyncReported;
/**
@@ -3944,24 +3938,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (isDragResizeChanged) {
setDragResizing();
}
- int resizeMode = RESIZE_MODE_INVALID;
- if (isDragResizing()) {
- switch (getResizeMode()) {
- case DRAG_RESIZE_MODE_FREEFORM:
- resizeMode = RESIZE_MODE_FREEFORM;
- break;
- case DRAG_RESIZE_MODE_DOCKED_DIVIDER:
- resizeMode = RESIZE_MODE_DOCKED_DIVIDER;
- break;
- }
- }
+ final boolean isDragResizing = isDragResizing();
markRedrawForSyncReported();
try {
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId,
- syncWithBuffers ? mSyncSeqId : -1, resizeMode);
+ syncWithBuffers ? mSyncSeqId : -1, isDragResizing);
if (drawPending && prevRotation >= 0 && prevRotation != mLastReportedConfiguration
.getMergedConfiguration().windowConfiguration.getRotation()) {
mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
@@ -4204,10 +4188,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
super.resetDragResizingChangeReported();
}
- int getResizeMode() {
- return mResizeMode;
- }
-
private boolean computeDragResizing() {
final Task task = getTask();
if (task == null) {
@@ -4230,8 +4210,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return true;
}
- return getDisplayContent().mDividerControllerLocked.isResizing()
- && !task.inFreeformWindowingMode() && !isGoneForLayout();
+ return false;
}
void setDragResizing() {
@@ -4240,25 +4219,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
mDragResizing = resizing;
- final Task task = getTask();
- if (task != null && task.isDragResizing()) {
- mResizeMode = task.getDragResizeMode();
- } else {
- mResizeMode = mDragResizing && getDisplayContent().mDividerControllerLocked.isResizing()
- ? DRAG_RESIZE_MODE_DOCKED_DIVIDER
- : DRAG_RESIZE_MODE_FREEFORM;
- }
}
boolean isDragResizing() {
return mDragResizing;
}
- boolean isDockedResizing() {
- return (mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER)
- || (isChildWindow() && getParentWindow().isDockedResizing());
- }
-
@CallSuper
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@@ -5934,10 +5900,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// level. Because the animation runs before display is rotated, task bounds should
// represent the frames in display space coordinates.
outFrame.set(getTask().getBounds());
- } else if (isDockedResizing()) {
- // If we are animating while docked resizing, then use the root task bounds as the
- // animation target (which will be different than the task bounds)
- outFrame.set(getTask().getParent().getBounds());
} else {
outFrame.set(getParentFrame());
}
diff --git a/services/core/jni/stats/SurfaceFlingerPuller.cpp b/services/core/jni/stats/SurfaceFlingerPuller.cpp
index 88736732a61c..b959798d0969 100644
--- a/services/core/jni/stats/SurfaceFlingerPuller.cpp
+++ b/services/core/jni/stats/SurfaceFlingerPuller.cpp
@@ -122,9 +122,12 @@ AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::parseLayerInfoPull(
for (const auto& atom : atomList.atom()) {
// The strings must outlive the BytesFields, which only have a pointer to the data.
std::string present2PresentStr, post2presentStr, acquire2PresentStr, latch2PresentStr,
- desired2PresentStr, post2AcquireStr, frameRateVoteStr, appDeadlineMissesStr;
+ desired2PresentStr, post2AcquireStr, frameRateVoteStr, appDeadlineMissesStr,
+ present2PresentDeltaStr;
optional<BytesField> present2Present =
getBytes(atom.present_to_present(), present2PresentStr);
+ optional<BytesField> present2PresentDelta =
+ getBytes(atom.present_to_present_delta(), present2PresentDeltaStr);
optional<BytesField> post2present = getBytes(atom.post_to_present(), post2presentStr);
optional<BytesField> acquire2Present =
getBytes(atom.acquire_to_present(), acquire2PresentStr);
@@ -138,7 +141,8 @@ AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::parseLayerInfoPull(
// Fail if any serialization to bytes failed.
if (!present2Present || !post2present || !acquire2Present || !latch2Present ||
- !desired2Present || !post2Acquire || !frameRateVote || !appDeadlineMisses) {
+ !desired2Present || !post2Acquire || !frameRateVote || !appDeadlineMisses ||
+ !present2PresentDelta) {
return AStatsManager_PULL_SKIP;
}
@@ -159,7 +163,7 @@ AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::parseLayerInfoPull(
atom.total_jank_frames_app_buffer_stuffing(),
atom.display_refresh_rate_bucket(), atom.render_rate_bucket(),
frameRateVote.value(), appDeadlineMisses.value(),
- atom.game_mode());
+ atom.game_mode(), present2PresentDelta.value());
}
return AStatsManager_PULL_SUCCESS;
}
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 b9140513d85b..f96c929375c5 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -44,9 +44,11 @@
</xs:element>
<xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0"
maxOccurs="1"/>
- <xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1" />
+ <xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1"/>
<xs:element type="autoBrightness" name="autoBrightness" minOccurs="0"
- maxOccurs="1" />
+ maxOccurs="1"/>
+ <xs:element type="refreshRateConfigs" name="refreshRate" minOccurs="0"
+ maxOccurs="1"/>
<xs:element type="nonNegativeDecimal" name="screenBrightnessRampFastDecrease">
<xs:annotation name="final"/>
</xs:element>
@@ -324,7 +326,7 @@
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
- </xs:complexType>
+ </xs:complexType>
<!-- Thresholds for brightness changes. -->
<xs:complexType name="thresholds">
@@ -452,4 +454,35 @@
</xs:element>
</xs:sequence>
</xs:complexType>
+
+ <xs:complexType name="refreshRateConfigs">
+ <xs:element name="lowerBlockingZoneConfigs" type="blockingZoneConfig"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="higherBlockingZoneConfigs" type="blockingZoneConfig"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:complexType>
+
+ <xs:complexType name="blockingZoneConfig">
+ <xs:element name="defaultRefreshRate" type="xs:nonNegativeInteger"
+ minOccurs="1" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="blockingZoneThreshold" type="blockingZoneThreshold"
+ minOccurs="1" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:complexType>
+
+ <xs:complexType name="blockingZoneThreshold">
+ <xs:sequence>
+ <xs:element name="displayBrightnessPoint" type="displayBrightnessPoint"
+ minOccurs="1" maxOccurs="unbounded">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
</xs:schema>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index d89bd7cc9aa2..6276edaf3ebc 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -13,6 +13,19 @@ package com.android.server.display.config {
method public void setEnabled(boolean);
}
+ public class BlockingZoneConfig {
+ ctor public BlockingZoneConfig();
+ method public final com.android.server.display.config.BlockingZoneThreshold getBlockingZoneThreshold();
+ method public final java.math.BigInteger getDefaultRefreshRate();
+ method public final void setBlockingZoneThreshold(com.android.server.display.config.BlockingZoneThreshold);
+ method public final void setDefaultRefreshRate(java.math.BigInteger);
+ }
+
+ public class BlockingZoneThreshold {
+ ctor public BlockingZoneThreshold();
+ method public final java.util.List<com.android.server.display.config.DisplayBrightnessPoint> getDisplayBrightnessPoint();
+ }
+
public class BrightnessThresholds {
ctor public BrightnessThresholds();
method public final com.android.server.display.config.ThresholdPoints getBrightnessThresholdPoints();
@@ -76,6 +89,7 @@ package com.android.server.display.config {
method public final com.android.server.display.config.SensorDetails getLightSensor();
method public final com.android.server.display.config.SensorDetails getProxSensor();
method public com.android.server.display.config.DisplayQuirks getQuirks();
+ method public com.android.server.display.config.RefreshRateConfigs getRefreshRate();
method @NonNull public final java.math.BigDecimal getScreenBrightnessDefault();
method @NonNull public final com.android.server.display.config.NitsMap getScreenBrightnessMap();
method public final java.math.BigInteger getScreenBrightnessRampDecreaseMaxMillis();
@@ -97,6 +111,7 @@ package com.android.server.display.config {
method public final void setLightSensor(com.android.server.display.config.SensorDetails);
method public final void setProxSensor(com.android.server.display.config.SensorDetails);
method public void setQuirks(com.android.server.display.config.DisplayQuirks);
+ method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs);
method public final void setScreenBrightnessDefault(@NonNull java.math.BigDecimal);
method public final void setScreenBrightnessMap(@NonNull com.android.server.display.config.NitsMap);
method public final void setScreenBrightnessRampDecreaseMaxMillis(java.math.BigInteger);
@@ -160,6 +175,14 @@ package com.android.server.display.config {
method public final void setValue(@NonNull java.math.BigDecimal);
}
+ public class RefreshRateConfigs {
+ ctor public RefreshRateConfigs();
+ method public final com.android.server.display.config.BlockingZoneConfig getHigherBlockingZoneConfigs();
+ method public final com.android.server.display.config.BlockingZoneConfig getLowerBlockingZoneConfigs();
+ method public final void setHigherBlockingZoneConfigs(com.android.server.display.config.BlockingZoneConfig);
+ method public final void setLowerBlockingZoneConfigs(com.android.server.display.config.BlockingZoneConfig);
+ }
+
public class RefreshRateRange {
ctor public RefreshRateRange();
method public final java.math.BigInteger getMaximum();
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index d3b9e10a436a..a92e4a18d609 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -20,6 +20,7 @@ import static android.content.Context.CREDENTIAL_SERVICE;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.credentials.ClearCredentialStateRequest;
@@ -30,13 +31,17 @@ import android.credentials.IClearCredentialStateCallback;
import android.credentials.ICreateCredentialCallback;
import android.credentials.ICredentialManager;
import android.credentials.IGetCredentialCallback;
+import android.credentials.IListEnabledProvidersCallback;
+import android.credentials.ListEnabledProvidersResponse;
+import android.credentials.ISetEnabledProvidersCallback;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.ICancellationSignal;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.credentials.BeginCreateCredentialRequest;
-import android.service.credentials.GetCredentialsRequest;
+import android.service.credentials.BeginGetCredentialsRequest;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -52,20 +57,23 @@ import java.util.stream.Collectors;
/**
* Entry point service for credential management.
*
- * <p>This service provides the {@link ICredentialManager} implementation and keeps a list of
- * {@link CredentialManagerServiceImpl} per user; the real work is done by
- * {@link CredentialManagerServiceImpl} itself.
+ * <p>This service provides the {@link ICredentialManager} implementation and keeps a list of {@link
+ * CredentialManagerServiceImpl} per user; the real work is done by {@link
+ * CredentialManagerServiceImpl} itself.
*/
-public final class CredentialManagerService extends
- AbstractMasterSystemService<CredentialManagerService, CredentialManagerServiceImpl> {
+public final class CredentialManagerService
+ extends AbstractMasterSystemService<
+ CredentialManagerService, CredentialManagerServiceImpl> {
private static final String TAG = "CredManSysService";
public CredentialManagerService(@NonNull Context context) {
- super(context,
- new SecureSettingsServiceNameResolver(context, Settings.Secure.CREDENTIAL_SERVICE,
- /*isMultipleMode=*/true),
- null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+ super(
+ context,
+ new SecureSettingsServiceNameResolver(
+ context, Settings.Secure.CREDENTIAL_SERVICE, /* isMultipleMode= */ true),
+ null,
+ PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
}
@Override
@@ -74,12 +82,14 @@ public final class CredentialManagerService extends
}
@Override // from AbstractMasterSystemService
- protected CredentialManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
- boolean disabled) {
+ protected CredentialManagerServiceImpl newServiceLocked(
+ @UserIdInt int resolvedUserId, boolean disabled) {
// This method should not be called for CredentialManagerService as it is configured to use
// multiple services.
- Slog.w(TAG, "Should not be here - CredentialManagerService is configured to use "
- + "multiple services");
+ Slog.w(
+ TAG,
+ "Should not be here - CredentialManagerService is configured to use "
+ + "multiple services");
return null;
}
@@ -89,8 +99,8 @@ public final class CredentialManagerService extends
}
@Override // from AbstractMasterSystemService
- protected List<CredentialManagerServiceImpl> newServiceListLocked(int resolvedUserId,
- boolean disabled, String[] serviceNames) {
+ protected List<CredentialManagerServiceImpl> newServiceListLocked(
+ int resolvedUserId, boolean disabled, String[] serviceNames) {
if (serviceNames == null || serviceNames.length == 0) {
Slog.i(TAG, "serviceNames sent in newServiceListLocked is null, or empty");
return new ArrayList<>();
@@ -102,8 +112,8 @@ public final class CredentialManagerService extends
continue;
}
try {
- serviceList.add(new CredentialManagerServiceImpl(this, mLock, resolvedUserId,
- serviceName));
+ serviceList.add(
+ new CredentialManagerServiceImpl(this, mLock, resolvedUserId, serviceName));
} catch (PackageManager.NameNotFoundException | SecurityException e) {
Log.i(TAG, "Unable to add serviceInfo : " + e.getMessage());
}
@@ -127,19 +137,20 @@ public final class CredentialManagerService extends
}
}
- private List<ProviderSession> initiateProviderSessions(RequestSession session,
- List<String> requestOptions) {
+ private List<ProviderSession> initiateProviderSessions(
+ RequestSession session, List<String> requestOptions) {
List<ProviderSession> providerSessions = new ArrayList<>();
// Invoke all services of a user to initiate a provider session
- runForUser((service) -> {
- if (service.isServiceCapable(requestOptions)) {
- ProviderSession providerSession = service
- .initiateProviderSessionForRequest(session);
- if (providerSession != null) {
- providerSessions.add(providerSession);
- }
- }
- });
+ runForUser(
+ (service) -> {
+ if (service.isServiceCapable(requestOptions)) {
+ ProviderSession providerSession =
+ service.initiateProviderSessionForRequest(session);
+ if (providerSession != null) {
+ providerSessions.add(providerSession);
+ }
+ }
+ });
return providerSessions;
}
@@ -154,25 +165,33 @@ public final class CredentialManagerService extends
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
// New request session, scoped for this request only.
- final GetRequestSession session = new GetRequestSession(getContext(),
- UserHandle.getCallingUserId(),
- callback,
- request,
- callingPackage);
+ final GetRequestSession session =
+ new GetRequestSession(
+ getContext(),
+ UserHandle.getCallingUserId(),
+ callback,
+ request,
+ callingPackage);
// Initiate all provider sessions
List<ProviderSession> providerSessions =
- initiateProviderSessions(session, request.getGetCredentialOptions()
- .stream().map(GetCredentialOption::getType)
- .collect(Collectors.toList()));
+ initiateProviderSessions(
+ session,
+ request.getGetCredentialOptions().stream()
+ .map(GetCredentialOption::getType)
+ .collect(Collectors.toList()));
// TODO : Return error when no providers available
// Iterate over all provider sessions and invoke the request
- providerSessions.forEach(providerGetSession -> {
- providerGetSession.getRemoteCredentialService().onGetCredentials(
- (GetCredentialsRequest) providerGetSession.getProviderRequest(),
- /*callback=*/providerGetSession);
- });
+ providerSessions.forEach(
+ providerGetSession -> {
+ providerGetSession
+ .getRemoteCredentialService()
+ .onBeginGetCredentials(
+ (BeginGetCredentialsRequest)
+ providerGetSession.getProviderRequest(),
+ /* callback= */ providerGetSession);
+ });
return cancelTransport;
}
@@ -186,11 +205,13 @@ public final class CredentialManagerService extends
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
// New request session, scoped for this request only.
- final CreateRequestSession session = new CreateRequestSession(getContext(),
- UserHandle.getCallingUserId(),
- request,
- callback,
- callingPackage);
+ final CreateRequestSession session =
+ new CreateRequestSession(
+ getContext(),
+ UserHandle.getCallingUserId(),
+ request,
+ callback,
+ callingPackage);
// Initiate all provider sessions
List<ProviderSession> providerSessions =
@@ -198,16 +219,83 @@ public final class CredentialManagerService extends
// TODO : Return error when no providers available
// Iterate over all provider sessions and invoke the request
- providerSessions.forEach(providerCreateSession -> {
- providerCreateSession.getRemoteCredentialService().onCreateCredential(
- (BeginCreateCredentialRequest)
- providerCreateSession.getProviderRequest(),
- /*callback=*/providerCreateSession);
- });
+ providerSessions.forEach(
+ providerCreateSession -> {
+ providerCreateSession
+ .getRemoteCredentialService()
+ .onCreateCredential(
+ (BeginCreateCredentialRequest)
+ providerCreateSession.getProviderRequest(),
+ /* callback= */ providerCreateSession);
+ });
+ return cancelTransport;
+ }
+
+ @Override
+ public ICancellationSignal listEnabledProviders(IListEnabledProvidersCallback callback) {
+ Log.i(TAG, "listEnabledProviders");
+ ICancellationSignal cancelTransport = CancellationSignal.createTransport();
+
+ List<String> enabledProviders = new ArrayList<>();
+ runForUser(
+ (service) -> {
+ enabledProviders.add(
+ service.getServiceInfo().getComponentName().flattenToString());
+ });
+
+ // Call the callback.
+ try {
+ callback.onResponse(ListEnabledProvidersResponse.create(enabledProviders));
+ } catch (RemoteException e) {
+ Log.i(TAG, "Issue with invoking response: " + e.getMessage());
+ // TODO: Propagate failure
+ }
+
return cancelTransport;
}
@Override
+ public void setEnabledProviders(
+ List<String> providers, int userId, ISetEnabledProvidersCallback callback) {
+ Log.i(TAG, "setEnabledProviders");
+
+ userId =
+ ActivityManager.handleIncomingUser(
+ Binder.getCallingPid(),
+ Binder.getCallingUid(),
+ userId,
+ false,
+ false,
+ "setEnabledProviders",
+ null);
+
+ String storedValue = String.join(":", providers);
+ if (!Settings.Secure.putStringForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.CREDENTIAL_SERVICE,
+ storedValue,
+ userId)) {
+ Log.e(TAG, "Failed to store setting containing enabled providers");
+ try {
+ callback.onError(
+ "failed_setting_store",
+ "Failed to store setting containing enabled providers");
+ } catch (RemoteException e) {
+ Log.i(TAG, "Issue with invoking error response: " + e.getMessage());
+ // TODO: Propagate failure
+ }
+ }
+
+ // Call the callback.
+ try {
+ callback.onResponse();
+ } catch (RemoteException e) {
+ Log.i(TAG, "Issue with invoking response: " + e.getMessage());
+ // TODO: Propagate failure
+ }
+ }
+
+ @Override
public ICancellationSignal clearCredentialState(ClearCredentialStateRequest request,
IClearCredentialStateCallback callback, String callingPackage) {
// TODO: implement.
diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
index d0bc0744f8a5..7f9e57a5bdb6 100644
--- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
+++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
@@ -19,7 +19,7 @@ package com.android.server.credentials;
import android.app.Activity;
import android.content.Intent;
import android.credentials.CreateCredentialResponse;
-import android.credentials.Credential;
+import android.credentials.GetCredentialResponse;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.service.credentials.CredentialProviderService;
import android.service.credentials.CredentialsResponseContent;
@@ -43,8 +43,7 @@ public class PendingIntentResultHandler {
return null;
}
return resultData.getParcelableExtra(
- CredentialProviderService
- .EXTRA_GET_CREDENTIALS_CONTENT_RESULT,
+ CredentialProviderService.EXTRA_CREDENTIALS_RESPONSE_CONTENT,
CredentialsResponseContent.class);
}
@@ -54,17 +53,17 @@ public class PendingIntentResultHandler {
return null;
}
return resultData.getParcelableExtra(
- CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESULT,
+ CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESPONSE,
CreateCredentialResponse.class);
}
- /** Extracts the {@link Credential} object added to the result data. */
- public static Credential extractCredential(Intent resultData) {
+ /** Extracts the {@link GetCredentialResponse} object added to the result data. */
+ public static GetCredentialResponse extractGetCredentialResponse(Intent resultData) {
if (resultData == null) {
return null;
}
return resultData.getParcelableExtra(
- CredentialProviderService.EXTRA_CREDENTIAL_RESULT,
- Credential.class);
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
+ GetCredentialResponse.class);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 6cd011b7a686..9888cc0a3732 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -19,19 +19,23 @@ package com.android.server.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.PendingIntent;
import android.content.Context;
-import android.credentials.Credential;
+import android.content.Intent;
import android.credentials.GetCredentialOption;
import android.credentials.GetCredentialResponse;
import android.credentials.ui.Entry;
import android.credentials.ui.GetCredentialProviderData;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.service.credentials.Action;
+import android.service.credentials.BeginGetCredentialOption;
+import android.service.credentials.BeginGetCredentialsRequest;
+import android.service.credentials.BeginGetCredentialsResponse;
import android.service.credentials.CredentialEntry;
import android.service.credentials.CredentialProviderInfo;
+import android.service.credentials.CredentialProviderService;
import android.service.credentials.CredentialsResponseContent;
-import android.service.credentials.GetCredentialsRequest;
-import android.service.credentials.GetCredentialsResponse;
+import android.service.credentials.GetCredentialRequest;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -41,6 +45,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.stream.Collectors;
/**
* Central provider session that listens for provider callbacks, and maintains provider state.
@@ -48,10 +53,10 @@ import java.util.UUID;
*
* @hide
*/
-public final class ProviderGetSession extends ProviderSession<GetCredentialsRequest,
- GetCredentialsResponse>
+public final class ProviderGetSession extends ProviderSession<BeginGetCredentialsRequest,
+ BeginGetCredentialsResponse>
implements
- RemoteCredentialService.ProviderCallbacks<GetCredentialsResponse> {
+ RemoteCredentialService.ProviderCallbacks<BeginGetCredentialsResponse> {
private static final String TAG = "ProviderGetSession";
// Key to be used as an entry key for a credential entry
@@ -69,6 +74,9 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
@Nullable
private Pair<String, Action> mUiAuthenticationAction = null;
+ /** The complete request to be used in the second round. */
+ private final GetCredentialRequest mCompleteRequest;
+
/** Creates a new provider session to be used by the request session. */
@Nullable public static ProviderGetSession createNewSession(
Context context,
@@ -76,20 +84,34 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
CredentialProviderInfo providerInfo,
GetRequestSession getRequestSession,
RemoteCredentialService remoteCredentialService) {
- GetCredentialsRequest providerRequest =
+ GetCredentialRequest completeRequest =
createProviderRequest(providerInfo.getCapabilities(),
getRequestSession.mClientRequest,
getRequestSession.mClientCallingPackage);
- if (providerRequest != null) {
+ if (completeRequest != null) {
+ // TODO: Update to using query data when ready
+ BeginGetCredentialsRequest beginGetCredentialsRequest =
+ new BeginGetCredentialsRequest.Builder(
+ completeRequest.getCallingPackage())
+ .setBeginGetCredentialOptions(
+ completeRequest.getGetCredentialOptions().stream().map(
+ option -> {
+ //TODO : Replace with option.getCandidateQueryData
+ // when ready
+ return new BeginGetCredentialOption(
+ option.getType(),
+ option.getCandidateQueryData());
+ }).collect(Collectors.toList()))
+ .build();
return new ProviderGetSession(context, providerInfo, getRequestSession, userId,
- remoteCredentialService, providerRequest);
+ remoteCredentialService, beginGetCredentialsRequest, completeRequest);
}
Log.i(TAG, "Unable to create provider session");
return null;
}
@Nullable
- private static GetCredentialsRequest createProviderRequest(List<String> providerCapabilities,
+ private static GetCredentialRequest createProviderRequest(List<String> providerCapabilities,
android.credentials.GetCredentialRequest clientRequest,
String clientCallingPackage) {
List<GetCredentialOption> filteredOptions = new ArrayList<>();
@@ -104,7 +126,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
}
}
if (!filteredOptions.isEmpty()) {
- return new GetCredentialsRequest.Builder(clientCallingPackage).setGetCredentialOptions(
+ return new GetCredentialRequest.Builder(clientCallingPackage).setGetCredentialOptions(
filteredOptions).build();
}
Log.i(TAG, "In createProviderRequest - returning null");
@@ -115,8 +137,10 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
CredentialProviderInfo info,
ProviderInternalCallback callbacks,
int userId, RemoteCredentialService remoteCredentialService,
- GetCredentialsRequest request) {
- super(context, info, request, callbacks, userId, remoteCredentialService);
+ BeginGetCredentialsRequest beginGetRequest,
+ GetCredentialRequest completeGetRequest) {
+ super(context, info, beginGetRequest, callbacks, userId, remoteCredentialService);
+ mCompleteRequest = completeGetRequest;
setStatus(Status.PENDING);
}
@@ -128,7 +152,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
/** Called when the provider response has been updated by an external source. */
@Override // Callback from the remote provider
- public void onProviderResponseSuccess(@Nullable GetCredentialsResponse response) {
+ public void onProviderResponseSuccess(@Nullable BeginGetCredentialsResponse response) {
Log.i(TAG, "in onProviderResponseSuccess");
onUpdateResponse(response);
}
@@ -254,19 +278,26 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
mUiCredentialEntries.put(entryId, credentialEntry);
Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
if (credentialEntry.getPendingIntent() != null) {
+ setUpFillInIntent(credentialEntry.getPendingIntent());
credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
credentialEntry.getSlice(), credentialEntry.getPendingIntent(),
/*fillInIntent=*/null));
- } else if (credentialEntry.getCredential() != null) {
- credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
- credentialEntry.getSlice()));
} else {
- Log.i(TAG, "No credential or pending intent. Should not happen.");
+ Log.i(TAG, "No pending intent. Should not happen.");
}
}
return credentialUiEntries;
}
+ private Intent setUpFillInIntent(PendingIntent pendingIntent) {
+ Intent intent = pendingIntent.getIntent();
+ intent.putExtra(
+ CredentialProviderService
+ .EXTRA_GET_CREDENTIAL_REQUEST,
+ mCompleteRequest);
+ return intent;
+ }
+
private List<Entry> prepareUiActionEntries(@Nullable List<Action> actions) {
List<Entry> actionEntries = new ArrayList<>();
for (Action action : actions) {
@@ -292,17 +323,14 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
private void onCredentialEntrySelected(CredentialEntry credentialEntry,
ProviderPendingIntentResponse providerPendingIntentResponse) {
- if (credentialEntry.getCredential() != null) {
- mCallbacks.onFinalResponseReceived(mComponentName, new GetCredentialResponse(
- credentialEntry.getCredential()));
- return;
- } else if (providerPendingIntentResponse != null) {
+ if (providerPendingIntentResponse != null) {
if (PendingIntentResultHandler.isSuccessfulResponse(providerPendingIntentResponse)) {
- Credential credential = PendingIntentResultHandler.extractCredential(
- providerPendingIntentResponse.getResultData());
- if (credential != null) {
- mCallbacks.onFinalResponseReceived(mComponentName,
- new GetCredentialResponse(credential));
+ // TODO: Remove credential extraction when flow is fully transitioned
+ GetCredentialResponse getCredentialResponse = PendingIntentResultHandler
+ .extractGetCredentialResponse(
+ providerPendingIntentResponse.getResultData());
+ if (getCredentialResponse != null) {
+ mCallbacks.onFinalResponseReceived(mComponentName, getCredentialResponse);
return;
}
}
@@ -320,7 +348,8 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
.extractResponseContent(providerPendingIntentResponse
.getResultData());
if (content != null) {
- onUpdateResponse(GetCredentialsResponse.createWithResponseContent(content));
+ onUpdateResponse(
+ BeginGetCredentialsResponse.createWithResponseContent(content));
return;
}
}
@@ -337,7 +366,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
/** Updates the response being maintained in state by this provider session. */
- private void onUpdateResponse(GetCredentialsResponse response) {
+ private void onUpdateResponse(BeginGetCredentialsResponse response) {
mProviderResponse = response;
if (response.getAuthenticationAction() != null) {
Log.i(TAG , "updateResponse with authentication entry");
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index e385bcb32201..7a883b359d9f 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -26,14 +26,14 @@ import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.service.credentials.BeginCreateCredentialRequest;
import android.service.credentials.BeginCreateCredentialResponse;
+import android.service.credentials.BeginGetCredentialsRequest;
+import android.service.credentials.BeginGetCredentialsResponse;
import android.service.credentials.CredentialProviderException;
import android.service.credentials.CredentialProviderException.CredentialProviderError;
import android.service.credentials.CredentialProviderService;
-import android.service.credentials.GetCredentialsRequest;
-import android.service.credentials.GetCredentialsResponse;
import android.service.credentials.IBeginCreateCredentialCallback;
+import android.service.credentials.IBeginGetCredentialsCallback;
import android.service.credentials.ICredentialProviderService;
-import android.service.credentials.IGetCredentialsCallback;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Slog;
@@ -106,19 +106,21 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
* @param callback the callback to be used to send back the provider response to the
* {@link ProviderGetSession} class that maintains provider state
*/
- public void onGetCredentials(@NonNull GetCredentialsRequest request,
- ProviderCallbacks<GetCredentialsResponse> callback) {
+ public void onBeginGetCredentials(@NonNull BeginGetCredentialsRequest request,
+ ProviderCallbacks<BeginGetCredentialsResponse> callback) {
Log.i(TAG, "In onGetCredentials in RemoteCredentialService");
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
- AtomicReference<CompletableFuture<GetCredentialsResponse>> futureRef =
+ AtomicReference<CompletableFuture<BeginGetCredentialsResponse>> futureRef =
new AtomicReference<>();
- CompletableFuture<GetCredentialsResponse> connectThenExecute = postAsync(service -> {
- CompletableFuture<GetCredentialsResponse> getCredentials = new CompletableFuture<>();
+ CompletableFuture<BeginGetCredentialsResponse> connectThenExecute = postAsync(service -> {
+ CompletableFuture<BeginGetCredentialsResponse> getCredentials =
+ new CompletableFuture<>();
ICancellationSignal cancellationSignal =
- service.onGetCredentials(request, new IGetCredentialsCallback.Stub() {
+ service.onBeginGetCredentials(request,
+ new IBeginGetCredentialsCallback.Stub() {
@Override
- public void onSuccess(GetCredentialsResponse response) {
+ public void onSuccess(BeginGetCredentialsResponse response) {
Log.i(TAG, "In onSuccess in RemoteCredentialService");
getCredentials.complete(response);
}
@@ -132,7 +134,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
errorCode, errorMsg));
}
});
- CompletableFuture<GetCredentialsResponse> future = futureRef.get();
+ CompletableFuture<BeginGetCredentialsResponse> future = futureRef.get();
if (future != null && future.isCancelled()) {
dispatchCancellationSignal(cancellationSignal);
} else {
@@ -159,7 +161,8 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef =
new AtomicReference<>();
- CompletableFuture<BeginCreateCredentialResponse> connectThenExecute = postAsync(service -> {
+ CompletableFuture<BeginCreateCredentialResponse> connectThenExecute =
+ postAsync(service -> {
CompletableFuture<BeginCreateCredentialResponse> createCredentialFuture =
new CompletableFuture<>();
ICancellationSignal cancellationSignal = service.onBeginCreateCredential(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 8047a534f4a3..9af30ba14b47 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -162,6 +162,7 @@ class ActiveAdmin {
private static final String TAG_PREFERENTIAL_NETWORK_SERVICE_CONFIG =
"preferential_network_service_config";
private static final String TAG_PROTECTED_PACKAGES = "protected_packages";
+ private static final String TAG_SUSPENDED_PACKAGES = "suspended-packages";
private static final String ATTR_VALUE = "value";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
@@ -257,6 +258,8 @@ class ActiveAdmin {
// List of packages for which the user cannot invoke "clear data" or "force stop".
List<String> protectedPackages;
+ List<String> suspendedPackages;
+
// Wi-Fi SSID restriction policy.
WifiSsidPolicy mWifiSsidPolicy;
@@ -508,6 +511,7 @@ class ActiveAdmin {
writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages);
writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages);
writePackageListToXml(out, TAG_PROTECTED_PACKAGES, protectedPackages);
+ writePackageListToXml(out, TAG_SUSPENDED_PACKAGES, suspendedPackages);
if (hasUserRestrictions()) {
UserRestrictionsUtils.writeRestrictions(
out, userRestrictions, TAG_USER_RESTRICTIONS);
@@ -776,6 +780,8 @@ class ActiveAdmin {
meteredDisabledPackages = readPackageList(parser, tag);
} else if (TAG_PROTECTED_PACKAGES.equals(tag)) {
protectedPackages = readPackageList(parser, tag);
+ } else if (TAG_SUSPENDED_PACKAGES.equals(tag)) {
+ suspendedPackages = readPackageList(parser, tag);
} else if (TAG_USER_RESTRICTIONS.equals(tag)) {
userRestrictions = UserRestrictionsUtils.readRestrictions(parser);
} else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) {
@@ -1225,6 +1231,11 @@ class ActiveAdmin {
pw.println(protectedPackages);
}
+ if (suspendedPackages != null) {
+ pw.print("suspendedPackages=");
+ pw.println(suspendedPackages);
+ }
+
pw.print("organizationColor=");
pw.println(organizationColor);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d91f63329af3..e93809d1b2c4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -336,7 +336,6 @@ import android.util.AtomicFile;
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
-import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -546,7 +545,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to
// be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade
// step.
- static final int DPMS_VERSION = 3;
+ static final int DPMS_VERSION = 4;
static {
SECURE_SETTINGS_ALLOWLIST = new ArraySet<>();
@@ -1220,6 +1219,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userHandle) == null) {
+ Slogf.e(LOG_TAG, String.format(
+ "Admin package %s not found for user %d, removing active admin",
+ packageName, userHandle));
removedAdmin = true;
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
@@ -1498,8 +1500,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
PackageManager getPackageManager(int userId) {
- return mContext
- .createContextAsUser(UserHandle.of(userId), 0 /* flags */).getPackageManager();
+ try {
+ return createContextAsUser(UserHandle.of(userId)).getPackageManager();
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
}
PowerManagerInternal getPowerManagerInternal() {
@@ -3112,6 +3117,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
List<UserInfo> allUsers = mUserManager.getUsers();
return allUsers.stream().mapToInt(u -> u.id).toArray();
}
+
+ @Override
+ public List<String> getPlatformSuspendedPackages(int userId) {
+ PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
+ return mInjector.getPackageManager(userId)
+ .getInstalledPackages(PackageManager.PackageInfoFlags.of(
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE))
+ .stream()
+ .map(packageInfo -> packageInfo.packageName)
+ .filter(pkg ->
+ PLATFORM_PACKAGE_NAME.equals(pmi.getSuspendingPackage(pkg, userId))
+ )
+ .collect(Collectors.toList());
+ }
}
private void performPolicyVersionUpgrade() {
@@ -3162,7 +3181,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
userId = mOwners.getDeviceOwnerUserId();
}
if (VERBOSE_LOG) {
- Log.v(LOG_TAG, "Starting non-system DO user: " + userId);
+ Slogf.v(LOG_TAG, "Starting non-system DO user: " + userId);
}
if (userId != UserHandle.USER_SYSTEM) {
try {
@@ -11384,6 +11403,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Slogf.w(LOG_TAG, "PM failed to suspend packages (%s)", Arrays.toString(packageNames));
return packageNames;
}
+
+ ArraySet<String> changed = new ArraySet<>(packageNames);
+ if (suspended) {
+ // Only save those packages that are actually suspended. If a package is exempt or is
+ // unsuspendable, it is skipped.
+ changed.removeAll(List.of(nonSuspendedPackages));
+ } else {
+ // If an admin tries to unsuspend a package that is either exempt or is not
+ // suspendable, drop it from the stored list assuming it must be already unsuspended.
+ changed.addAll(exemptApps);
+ }
+
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
+ ArraySet<String> current = new ArraySet<>(admin.suspendedPackages);
+ if (suspended) {
+ current.addAll(changed);
+ } else {
+ current.removeAll(changed);
+ }
+ admin.suspendedPackages = current.isEmpty() ? null : new ArrayList<>(current);
+ saveSettingsLocked(caller.getUserId());
+ }
+
if (exemptApps.isEmpty()) {
return nonSuspendedPackages;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
index 147474907f29..c0ef0b0f80df 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import com.android.internal.util.JournaledFile;
+import java.util.List;
import java.util.function.Function;
/**
@@ -48,4 +49,9 @@ public interface PolicyUpgraderDataProvider {
* Returns the users to upgrade.
*/
int[] getUsersForUpgrade();
+
+ /**
+ * Returns packages suspended by platform for a given user.
+ */
+ List<String> getPlatformSuspendedPackages(int userId);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 808133164cd1..1fe4b571a770 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -104,6 +104,12 @@ public class PolicyVersionUpgrader {
currentVersion = 3;
}
+ if (currentVersion == 3) {
+ Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion));
+ upgradePackageSuspension(allUsers, ownersData, allUsersData);
+ currentVersion = 4;
+ }
+
writePoliciesAndVersion(allUsers, allUsersData, ownersData, currentVersion);
}
@@ -170,6 +176,44 @@ public class PolicyVersionUpgrader {
}
}
+ /**
+ * This upgrade step stores packages suspended via DPM.setPackagesSuspended() into ActiveAdmin
+ * data structure. Prior to this it was only persisted in PackageManager which doesn't have any
+ * way of knowing which admin suspended it.
+ */
+ private void upgradePackageSuspension(
+ int[] allUsers, OwnersData ownersData, SparseArray<DevicePolicyData> allUsersData) {
+ if (ownersData.mDeviceOwner != null) {
+ saveSuspendedPackages(allUsersData, ownersData.mDeviceOwnerUserId,
+ ownersData.mDeviceOwner.admin);
+ }
+
+ for (int i = 0; i < ownersData.mProfileOwners.size(); i++) {
+ int ownerUserId = ownersData.mProfileOwners.keyAt(i);
+ OwnersData.OwnerInfo ownerInfo = ownersData.mProfileOwners.valueAt(i);
+ saveSuspendedPackages(allUsersData, ownerUserId, ownerInfo.admin);
+ }
+ }
+
+ private void saveSuspendedPackages(SparseArray<DevicePolicyData> allUsersData, int ownerUserId,
+ ComponentName ownerPackage) {
+ DevicePolicyData ownerUserData = allUsersData.get(ownerUserId);
+ if (ownerUserData == null) {
+ Slog.e(LOG_TAG, "No policy data for owner user, cannot migrate suspended packages");
+ return;
+ }
+
+ ActiveAdmin ownerAdmin = ownerUserData.mAdminMap.get(ownerPackage);
+ if (ownerAdmin == null) {
+ Slog.e(LOG_TAG, "No admin for owner, cannot migrate suspended packages");
+ return;
+ }
+
+ ownerAdmin.suspendedPackages = mProvider.getPlatformSuspendedPackages(ownerUserId);
+ Slog.i(LOG_TAG, String.format("Saved %d packages suspended by %s in user %d",
+ ownerAdmin.suspendedPackages.size(), ownerPackage, ownerUserId));
+ }
+
private OwnersData loadOwners(int[] allUsers) {
OwnersData ownersData = new OwnersData(mPathProvider);
ownersData.load(allUsers);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e41e781b7c22..509d75bf9b76 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -154,6 +154,7 @@ import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.NativeTombstoneManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.people.PeopleService;
+import com.android.server.permission.access.AccessCheckingService;
import com.android.server.pm.ApexManager;
import com.android.server.pm.ApexSystemServiceInfo;
import com.android.server.pm.BackgroundInstallControlService;
@@ -1110,6 +1111,11 @@ public final class SystemServer implements Dumpable {
startMemtrackProxyService();
t.traceEnd();
+ // Start AccessCheckingService which provides new implementation for permission and app op.
+ t.traceBegin("StartAccessCheckingService");
+ mSystemServiceManager.startService(AccessCheckingService.class);
+ t.traceEnd();
+
// Activity manager runs the show.
t.traceBegin("StartActivityManager");
// TODO: Might need to move after migration to WM.
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index b519a782ce26..4aba30a661ad 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -23,7 +23,6 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-// import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -31,6 +30,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.XmlResourceParser;
+import android.media.MediaMetrics;
import android.media.midi.IBluetoothMidiService;
import android.media.midi.IMidiDeviceListener;
import android.media.midi.IMidiDeviceOpenCallback;
@@ -63,12 +63,16 @@ import org.xmlpull.v1.XmlPullParser;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
// NOTE about locking order:
// if there is a path that syncs on BOTH mDevicesByInfo AND mDeviceConnections,
@@ -359,6 +363,17 @@ public class MidiService extends IMidiManager.Stub {
private final ArrayList<DeviceConnection> mDeviceConnections
= new ArrayList<DeviceConnection>();
+ // Keep track of number of added and removed collections for logging
+ private AtomicInteger mDeviceConnectionsAdded = new AtomicInteger();
+ private AtomicInteger mDeviceConnectionsRemoved = new AtomicInteger();
+
+ // Keep track of total time with at least one active connection
+ private AtomicLong mTotalTimeConnectedNs = new AtomicLong();
+ private Instant mPreviousCounterInstant = null;
+
+ private AtomicInteger mTotalInputBytes = new AtomicInteger();
+ private AtomicInteger mTotalOutputBytes = new AtomicInteger();
+
public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo,
ServiceInfo serviceInfo, int uid) {
mDeviceInfo = deviceInfo;
@@ -460,6 +475,11 @@ public class MidiService extends IMidiManager.Stub {
public void addDeviceConnection(DeviceConnection connection) {
Log.d(TAG, "addDeviceConnection() [A] connection:" + connection);
synchronized (mDeviceConnections) {
+ mDeviceConnectionsAdded.incrementAndGet();
+ if (mPreviousCounterInstant == null) {
+ mPreviousCounterInstant = Instant.now();
+ }
+
Log.d(TAG, " mServer:" + mServer);
if (mServer != null) {
Log.i(TAG, "++++ A");
@@ -533,6 +553,20 @@ public class MidiService extends IMidiManager.Stub {
public void removeDeviceConnection(DeviceConnection connection) {
synchronized (mDevicesByInfo) {
synchronized (mDeviceConnections) {
+ int numRemovedConnections = mDeviceConnectionsRemoved.incrementAndGet();
+ if (mPreviousCounterInstant != null) {
+ mTotalTimeConnectedNs.addAndGet(Duration.between(
+ mPreviousCounterInstant, Instant.now()).toNanos());
+ }
+ // Stop the clock if all devices have been removed.
+ // Otherwise, start the clock from the current instant.
+ if (numRemovedConnections >= mDeviceConnectionsAdded.get()) {
+ mPreviousCounterInstant = null;
+ } else {
+ mPreviousCounterInstant = Instant.now();
+ }
+ logMetrics(false /* isDeviceDisconnected */);
+
mDeviceConnections.remove(connection);
if (connection.getDevice().getDeviceInfo().getType()
@@ -569,6 +603,16 @@ public class MidiService extends IMidiManager.Stub {
connection.getClient().removeDeviceConnection(connection);
}
mDeviceConnections.clear();
+
+ // If the timer is still going, some clients have not closed the connection yet.
+ if (mPreviousCounterInstant != null) {
+ Instant currentInstant = Instant.now();
+ mTotalTimeConnectedNs.addAndGet(Duration.between(
+ mPreviousCounterInstant, currentInstant).toNanos());
+ mPreviousCounterInstant = currentInstant;
+ }
+
+ logMetrics(true /* isDeviceDisconnected */);
}
setDeviceServer(null);
@@ -585,6 +629,35 @@ public class MidiService extends IMidiManager.Stub {
}
}
+ private void logMetrics(boolean isDeviceDisconnected) {
+ // Only log metrics if the device was used in a connection
+ int numDeviceConnectionAdded = mDeviceConnectionsAdded.get();
+ if (mDeviceInfo != null && numDeviceConnectionAdded > 0) {
+ new MediaMetrics.Item(MediaMetrics.Name.AUDIO_MIDI)
+ .setUid(mUid)
+ .set(MediaMetrics.Property.DEVICE_ID, mDeviceInfo.getId())
+ .set(MediaMetrics.Property.INPUT_PORT_COUNT, mDeviceInfo.getInputPortCount())
+ .set(MediaMetrics.Property.OUTPUT_PORT_COUNT,
+ mDeviceInfo.getOutputPortCount())
+ .set(MediaMetrics.Property.HARDWARE_TYPE, mDeviceInfo.getType())
+ .set(MediaMetrics.Property.DURATION_NS, mTotalTimeConnectedNs.get())
+ .set(MediaMetrics.Property.OPENED_COUNT, numDeviceConnectionAdded)
+ .set(MediaMetrics.Property.CLOSED_COUNT, mDeviceConnectionsRemoved.get())
+ .set(MediaMetrics.Property.DEVICE_DISCONNECTED,
+ isDeviceDisconnected ? "true" : "false")
+ .set(MediaMetrics.Property.IS_SHARED,
+ !mDeviceInfo.isPrivate() ? "true" : "false")
+ .set(MediaMetrics.Property.SUPPORTS_MIDI_UMP, mDeviceInfo.getDefaultProtocol()
+ != MidiDeviceInfo.PROTOCOL_UNKNOWN ? "true" : "false")
+ .set(MediaMetrics.Property.USING_ALSA, mDeviceInfo.getProperties().get(
+ MidiDeviceInfo.PROPERTY_ALSA_CARD) != null ? "true" : "false")
+ .set(MediaMetrics.Property.EVENT, "deviceClosed")
+ .set(MediaMetrics.Property.TOTAL_INPUT_BYTES, mTotalInputBytes.get())
+ .set(MediaMetrics.Property.TOTAL_OUTPUT_BYTES, mTotalOutputBytes.get())
+ .record();
+ }
+ }
+
@Override
public void binderDied() {
Log.d(TAG, "Device died: " + this);
@@ -593,6 +666,11 @@ public class MidiService extends IMidiManager.Stub {
}
}
+ public void updateTotalBytes(int totalInputBytes, int totalOutputBytes) {
+ mTotalInputBytes.set(totalInputBytes);
+ mTotalOutputBytes.set(totalOutputBytes);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Device Info: ");
@@ -1373,6 +1451,17 @@ public class MidiService extends IMidiManager.Stub {
}
@Override
+ public void updateTotalBytes(IMidiDeviceServer server, int totalInputBytes,
+ int totalOutputBytes) {
+ synchronized (mDevicesByInfo) {
+ Device device = mDevicesByServer.get(server.asBinder());
+ if (device != null) {
+ device.updateTotalBytes(totalInputBytes, totalOutputBytes);
+ }
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
diff --git a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
index 7b96d42c8abe..73c2cccc550d 100644
--- a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
@@ -16,11 +16,23 @@
package com.android.server.permission.access
+import android.content.Context
import com.android.internal.annotations.Keep
-import com.android.server.permission.access.external.PackageState
+import com.android.server.LocalManagerRegistry
+import com.android.server.LocalServices
+import com.android.server.SystemService
+import com.android.server.appop.AppOpsCheckingServiceInterface
+import com.android.server.permission.access.appop.AppOpService
+import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
+import com.android.server.permission.access.permission.PermissionService
+import com.android.server.pm.PackageManagerLocal
+import com.android.server.pm.UserManagerService
+import com.android.server.pm.permission.PermissionManagerServiceInterface
+import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.pm.pkg.PackageState
@Keep
-class AccessCheckingService {
+class AccessCheckingService(context: Context) : SystemService(context) {
@Volatile
private lateinit var state: AccessState
private val stateLock = Any()
@@ -29,14 +41,35 @@ class AccessCheckingService {
private val persistence = AccessPersistence(policy)
- fun init() {
+ private lateinit var appOpService: AppOpService
+ private lateinit var permissionService: PermissionService
+
+ private lateinit var packageManagerLocal: PackageManagerLocal
+ private lateinit var userManagerService: UserManagerService
+
+ override fun onStart() {
+ appOpService = AppOpService(this)
+ permissionService = PermissionService(this)
+
+ LocalServices.addService(AppOpsCheckingServiceInterface::class.java, appOpService)
+ LocalServices.addService(PermissionManagerServiceInterface::class.java, permissionService)
+ }
+
+ fun initialize() {
+ packageManagerLocal =
+ LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
+ userManagerService = UserManagerService.getInstance()
+
+ val userIds = IntSet(userManagerService.userIdsIncludingPreCreated)
+ val packageStates = packageManagerLocal.packageStates
+
val state = AccessState()
- state.systemState.userIds.apply {
- // TODO: Get and add all user IDs.
- // TODO: Maybe get and add all packages?
- }
+ policy.initialize(state, userIds, packageStates)
persistence.read(state)
this.state = state
+
+ appOpService.initialize()
+ permissionService.initialize()
}
fun getDecision(subject: AccessUri, `object`: AccessUri): Int =
@@ -50,30 +83,60 @@ class AccessCheckingService {
}
}
- fun onUserAdded(userId: Int) {
+ internal fun onUserAdded(userId: Int) {
mutateState {
with(policy) { onUserAdded(userId) }
}
}
- fun onUserRemoved(userId: Int) {
+ internal fun onUserRemoved(userId: Int) {
mutateState {
with(policy) { onUserRemoved(userId) }
}
}
- fun onPackageAdded(packageState: PackageState) {
+ internal fun onStorageVolumeMounted(volumeUuid: String?, isSystemUpdated: Boolean) {
+ val packageStates = packageManagerLocal.packageStates
+ mutateState {
+ with(policy) { onStorageVolumeMounted(packageStates, volumeUuid, isSystemUpdated) }
+ }
+ }
+
+ internal fun onPackageAdded(packageName: String) {
+ val packageStates = packageManagerLocal.packageStates
+ mutateState {
+ with(policy) { onPackageAdded(packageStates, packageName) }
+ }
+ }
+
+ internal fun onPackageRemoved(packageName: String, appId: Int) {
+ val packageStates = packageManagerLocal.packageStates
mutateState {
- with(policy) { onPackageAdded(packageState) }
+ with(policy) { onPackageRemoved(packageStates, packageName, appId) }
}
}
- fun onPackageRemoved(packageState: PackageState) {
+ internal fun onPackageInstalled(
+ packageName: String,
+ params: PermissionManagerServiceInternal.PackageInstalledParams,
+ userId: Int
+ ) {
+ val packageStates = packageManagerLocal.packageStates
mutateState {
- with(policy) { onPackageRemoved(packageState) }
+ with(policy) { onPackageInstalled(packageStates, packageName, params, userId) }
}
}
+ internal fun onPackageUninstalled(packageName: String, appId: Int, userId: Int) {
+ val packageStates = packageManagerLocal.packageStates
+ mutateState {
+ with(policy) { onPackageUninstalled(packageStates, packageName, appId, userId) }
+ }
+ }
+
+ private val PackageManagerLocal.packageStates: Map<String, PackageState>
+ get() = withUnfilteredSnapshot().use { it.packageStates }
+
internal inline fun <T> getState(action: GetStateScope.() -> T): T =
GetStateScope(state).action()
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index e9741c69aa5b..0201dd0d0c79 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -22,11 +22,12 @@ import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.appop.PackageAppOpPolicy
import com.android.server.permission.access.appop.UidAppOpPolicy
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.external.PackageState
import com.android.server.permission.access.permission.UidPermissionPolicy
import com.android.server.permission.access.util.forEachTag
import com.android.server.permission.access.util.tag
import com.android.server.permission.access.util.tagName
+import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.pm.pkg.PackageState
class AccessPolicy private constructor(
private val schemePolicies: IndexedMap<String, IndexedMap<String, SchemePolicy>>
@@ -53,6 +54,17 @@ class AccessPolicy private constructor(
with(getSchemePolicy(subject, `object`)) { setDecision(subject, `object`, decision) }
}
+ fun initialize(state: AccessState, userIds: IntSet, packageStates: Map<String, PackageState>) {
+ state.systemState.apply {
+ this.userIds += userIds
+ this.packageStates = packageStates
+ packageStates.forEach { (_, packageState) ->
+ appIds.getOrPut(packageState.appId) { IndexedListSet() }
+ .add(packageState.packageName)
+ }
+ }
+ }
+
fun MutateStateScope.onUserAdded(userId: Int) {
newState.systemState.userIds += userId
newState.userStates[userId] = UserState()
@@ -69,18 +81,34 @@ class AccessPolicy private constructor(
}
}
- fun MutateStateScope.onPackageAdded(packageState: PackageState) {
- var isAppIdAdded = false
- newState.systemState.apply {
- packageStates[packageState.packageName] = packageState
- appIds.getOrPut(packageState.appId) {
- isAppIdAdded = true
- IndexedListSet()
- }.add(packageState.packageName)
+ fun MutateStateScope.onStorageVolumeMounted(
+ packageStates: Map<String, PackageState>,
+ volumeUuid: String?,
+ isSystemUpdated: Boolean
+ ) {
+ newState.systemState.packageStates = packageStates
+ forEachSchemePolicy {
+ with(it) { onStorageVolumeMounted(volumeUuid, isSystemUpdated) }
}
+ }
+
+ fun MutateStateScope.onPackageAdded(
+ packageStates: Map<String, PackageState>,
+ packageName: String
+ ) {
+ newState.systemState.packageStates = packageStates
+ var isAppIdAdded = false
+ val packageState = packageStates[packageName]
+ // TODO(zhanghai): Remove check before submission.
+ checkNotNull(packageState)
+ val appId = packageState.appId
+ newState.systemState.appIds.getOrPut(appId) {
+ isAppIdAdded = true
+ IndexedListSet()
+ }.add(packageName)
if (isAppIdAdded) {
forEachSchemePolicy {
- with(it) { onAppIdAdded(packageState.appId) }
+ with(it) { onAppIdAdded(appId) }
}
}
forEachSchemePolicy {
@@ -88,30 +116,61 @@ class AccessPolicy private constructor(
}
}
- fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
+ fun MutateStateScope.onPackageRemoved(
+ packageStates: Map<String, PackageState>,
+ packageName: String,
+ appId: Int
+ ) {
+ newState.systemState.packageStates = packageStates
var isAppIdRemoved = false
- newState.systemState.apply {
- packageStates -= packageState.packageName
- appIds.apply appIds@{
- this[packageState.appId]?.apply {
- this -= packageState.packageName
- if (isEmpty()) {
- this@appIds -= packageState.appId
- isAppIdRemoved = true
- }
+ // TODO(zhanghai): Remove check before submission.
+ check(packageName !in packageStates)
+ newState.systemState.appIds.apply appIds@{
+ this[appId]?.apply {
+ this -= packageName
+ if (isEmpty()) {
+ this@appIds -= appId
+ isAppIdRemoved = true
}
}
}
forEachSchemePolicy {
- with(it) { onPackageRemoved(packageState) }
+ with(it) { onPackageRemoved(packageName, appId) }
}
if (isAppIdRemoved) {
forEachSchemePolicy {
- with(it) { onAppIdRemoved(packageState.appId) }
+ with(it) { onAppIdRemoved(appId) }
}
}
}
+ fun MutateStateScope.onPackageInstalled(
+ packageStates: Map<String, PackageState>,
+ packageName: String,
+ params: PermissionManagerServiceInternal.PackageInstalledParams,
+ userId: Int
+ ) {
+ newState.systemState.packageStates = packageStates
+ val packageState = packageStates[packageName]
+ // TODO(zhanghai): Remove check before submission.
+ checkNotNull(packageState)
+ forEachSchemePolicy {
+ with(it) { onPackageInstalled(packageState, params, userId) }
+ }
+ }
+
+ fun MutateStateScope.onPackageUninstalled(
+ packageStates: Map<String, PackageState>,
+ packageName: String,
+ appId: Int,
+ userId: Int
+ ) {
+ newState.systemState.packageStates = packageStates
+ forEachSchemePolicy {
+ with(it) { onPackageUninstalled(packageName, appId, userId) }
+ }
+ }
+
fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {
forEachTag {
when (tagName) {
@@ -230,9 +289,22 @@ abstract class SchemePolicy {
open fun MutateStateScope.onAppIdRemoved(appId: Int) {}
+ open fun MutateStateScope.onStorageVolumeMounted(
+ volumeUuid: String?,
+ isSystemUpdated: Boolean
+ ) {}
+
open fun MutateStateScope.onPackageAdded(packageState: PackageState) {}
- open fun MutateStateScope.onPackageRemoved(packageState: PackageState) {}
+ open fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {}
+
+ open fun MutateStateScope.onPackageInstalled(
+ packageState: PackageState,
+ params: PermissionManagerServiceInternal.PackageInstalledParams,
+ userId: Int
+ ) {}
+
+ open fun MutateStateScope.onPackageUninstalled(packageName: String, appId: Int, userId: Int) {}
open fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {}
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index cf8f38360cff..4a2c78a86a93 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -18,8 +18,8 @@ package com.android.server.permission.access
import android.content.pm.PermissionGroupInfo
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.data.Permission
-import com.android.server.permission.access.external.PackageState
+import com.android.server.permission.access.permission.Permission
+import com.android.server.pm.pkg.PackageState
class AccessState private constructor(
val systemState: SystemState,
@@ -32,8 +32,8 @@ class AccessState private constructor(
class SystemState private constructor(
val userIds: IntSet,
- val packageStates: IndexedMap<String, PackageState>,
- val disabledSystemPackageStates: IndexedMap<String, PackageState>,
+ var packageStates: Map<String, PackageState>,
+ var disabledSystemPackageStates: Map<String, PackageState>,
val appIds: IntMap<IndexedListSet<String>>,
// A map of KnownPackagesInt to a set of known package names
val knownPackages: IntMap<IndexedListSet<String>>,
@@ -59,7 +59,7 @@ class SystemState private constructor(
val permissions: IndexedMap<String, Permission>
) : WritableState() {
constructor() : this(
- IntSet(), IndexedMap(), IndexedMap(), IntMap(), IntMap(), IntMap(), IndexedMap(),
+ IntSet(), emptyMap(), emptyMap(), IntMap(), IntMap(), IntMap(), IndexedMap(),
IndexedListSet(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(),
IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(),
IndexedMap(), IndexedMap(), IndexedMap()
@@ -68,8 +68,8 @@ class SystemState private constructor(
fun copy(): SystemState =
SystemState(
userIds.copy(),
- packageStates.copy { it },
- disabledSystemPackageStates.copy { it },
+ packageStates,
+ disabledSystemPackageStates,
appIds.copy { it.copy() },
knownPackages.copy { it.copy() },
deviceAndProfileOwners.copy { it },
@@ -94,14 +94,17 @@ class SystemState private constructor(
class UserState private constructor(
// A map of (appId to a map of (permissionName to permissionFlags))
- val permissionFlags: IntMap<IndexedMap<String, Int>>,
+ val uidPermissionFlags: IntMap<IndexedMap<String, Int>>,
val uidAppOpModes: IntMap<IndexedMap<String, Int>>,
val packageAppOpModes: IndexedMap<String, IndexedMap<String, Int>>
) : WritableState() {
constructor() : this(IntMap(), IntMap(), IndexedMap())
- fun copy(): UserState = UserState(permissionFlags.copy { it.copy { it } },
- uidAppOpModes.copy { it.copy { it } }, packageAppOpModes.copy { it.copy { it } })
+ fun copy(): UserState = UserState(
+ uidPermissionFlags.copy { it.copy { it } },
+ uidAppOpModes.copy { it.copy { it } },
+ packageAppOpModes.copy { it.copy { it } }
+ )
}
object WriteMode {
diff --git a/services/permission/java/com/android/server/permission/access/AccessUri.kt b/services/permission/java/com/android/server/permission/access/AccessUri.kt
index 7e98d2cb13e7..d1abc0455245 100644
--- a/services/permission/java/com/android/server/permission/access/AccessUri.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessUri.kt
@@ -16,8 +16,7 @@
package com.android.server.permission.access
-import com.android.server.permission.access.external.UserHandle
-import com.android.server.permission.access.external.UserHandleCompat
+import android.os.UserHandle
sealed class AccessUri(
val scheme: String
@@ -70,7 +69,7 @@ data class UidUri(
val uid: Int
) : AccessUri(SCHEME) {
val userId: Int
- get() = UserHandleCompat.getUserId(uid)
+ get() = UserHandle.getUserId(uid)
val appId: Int
get() = UserHandle.getAppId(uid)
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppOpsCheckingServiceCompatImpl.kt b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
index a565feb959c2..b8d6aa3b4e49 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppOpsCheckingServiceCompatImpl.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
@@ -24,9 +24,13 @@ import com.android.server.appop.OnOpModeChangedListener
import com.android.server.permission.access.AccessCheckingService
import java.io.PrintWriter
-class AppOpsCheckingServiceCompatImpl(
- private val accessCheckingService: AccessCheckingService
+class AppOpService(
+ private val service: AccessCheckingService
) : AppOpsCheckingServiceInterface {
+ fun initialize() {
+ TODO("Not yet implemented")
+ }
+
override fun getNonDefaultUidModes(uid: Int): SparseIntArray {
TODO("Not yet implemented")
}
@@ -139,6 +143,6 @@ class AppOpsCheckingServiceCompatImpl(
}
companion object {
- private val LOG_TAG = AppOpsCheckingServiceCompatImpl::class.java.simpleName
+ private val LOG_TAG = AppOpService::class.java.simpleName
}
}
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
index 966489f72aa2..f4d6bfd0a000 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
@@ -23,7 +23,6 @@ import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PackageUri
import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.external.PackageState
class PackageAppOpPolicy : BaseAppOpPolicy(PackageAppOpPersistence()) {
override val subjectScheme: String
@@ -48,9 +47,9 @@ class PackageAppOpPolicy : BaseAppOpPolicy(PackageAppOpPersistence()) {
newState.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
}
- override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
+ override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
- userState.packageAppOpModes -= packageState.packageName
+ userState.packageAppOpModes -= packageName
}
}
}
diff --git a/services/permission/java/com/android/server/permission/access/collection/IndexedList.kt b/services/permission/java/com/android/server/permission/access/collection/IndexedList.kt
index 5ba435c79e2f..9cb2e8660e78 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IndexedList.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IndexedList.kt
@@ -72,18 +72,24 @@ inline operator fun <T> IndexedList<T>.plusAssign(element: T) {
add(element)
}
-inline fun <T> IndexedList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> IndexedList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, this[index])) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
-inline fun <T> IndexedList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> IndexedList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, this[index])) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
diff --git a/services/permission/java/com/android/server/permission/access/collection/IndexedListSet.kt b/services/permission/java/com/android/server/permission/access/collection/IndexedListSet.kt
index ac552fff6cdb..1c42c50e0241 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IndexedListSet.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IndexedListSet.kt
@@ -123,18 +123,24 @@ inline operator fun <T> IndexedListSet<T>.plusAssign(element: T) {
add(element)
}
-inline fun <T> IndexedListSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> IndexedListSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, elementAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
-inline fun <T> IndexedListSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> IndexedListSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, elementAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
diff --git a/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt b/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt
index 1251666089f5..2448ff0755be 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt
@@ -111,20 +111,26 @@ inline fun <K, V> IndexedMap<K, V>.putWithDefault(key: K, value: V, defaultValue
}
}
-inline fun <K, V> IndexedMap<K, V>.removeAllIndexed(predicate: (Int, K, V) -> Boolean) {
+inline fun <K, V> IndexedMap<K, V>.removeAllIndexed(predicate: (Int, K, V) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
-inline fun <K, V> IndexedMap<K, V>.retainAllIndexed(predicate: (Int, K, V) -> Boolean) {
+inline fun <K, V> IndexedMap<K, V>.retainAllIndexed(predicate: (Int, K, V) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
@Suppress("NOTHING_TO_INLINE")
diff --git a/services/permission/java/com/android/server/permission/access/collection/IndexedSet.kt b/services/permission/java/com/android/server/permission/access/collection/IndexedSet.kt
index 36d8ff0c0087..faaa6d3a23f1 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IndexedSet.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IndexedSet.kt
@@ -80,20 +80,26 @@ inline operator fun <T> IndexedSet<T>.plusAssign(element: T) {
add(element)
}
-inline fun <T> IndexedSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> IndexedSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, elementAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
-inline fun <T> IndexedSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> IndexedSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, elementAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
@Suppress("NOTHING_TO_INLINE")
diff --git a/services/permission/java/com/android/server/permission/access/collection/IntMap.kt b/services/permission/java/com/android/server/permission/access/collection/IntMap.kt
index 9051c66120d8..0044b7359ef3 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IntMap.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IntMap.kt
@@ -120,20 +120,26 @@ inline fun <T> IntMap<T>.putWithDefault(key: Int, value: T, defaultValue: T): T
}
}
-inline fun <T> IntMap<T>.removeAllIndexed(predicate: (Int, Int, T) -> Boolean) {
+inline fun <T> IntMap<T>.removeAllIndexed(predicate: (Int, Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
-inline fun <T> IntMap<T>.retainAllIndexed(predicate: (Int, Int, T) -> Boolean) {
+inline fun <T> IntMap<T>.retainAllIndexed(predicate: (Int, Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
inline val <T> IntMap<T>.size: Int
diff --git a/services/permission/java/com/android/server/permission/access/collection/IntSet.kt b/services/permission/java/com/android/server/permission/access/collection/IntSet.kt
index d6dfe9d0eb37..0d75a4c87a89 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IntSet.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IntSet.kt
@@ -51,6 +51,8 @@ class IntSet private constructor(
fun copy(): IntSet = IntSet(array.clone())
}
+fun IntSet(values: IntArray): IntSet = IntSet().apply{ this += values }
+
inline fun IntSet.allIndexed(predicate: (Int, Int) -> Boolean): Boolean {
for (index in 0 until size) {
if (!predicate(index, elementAt(index))) {
@@ -103,18 +105,32 @@ inline operator fun IntSet.plusAssign(element: Int) {
add(element)
}
-inline fun IntSet.removeAllIndexed(predicate: (Int, Int) -> Boolean) {
+operator fun IntSet.plusAssign(set: IntSet) {
+ set.forEachIndexed { _, it -> this += it }
+}
+
+operator fun IntSet.plusAssign(array: IntArray) {
+ array.forEach { this += it }
+}
+
+inline fun IntSet.removeAllIndexed(predicate: (Int, Int) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, elementAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
-inline fun IntSet.retainAllIndexed(predicate: (Int, Int) -> Boolean) {
+inline fun IntSet.retainAllIndexed(predicate: (Int, Int) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, elementAt(index))) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
diff --git a/services/permission/java/com/android/server/permission/access/collection/List.kt b/services/permission/java/com/android/server/permission/access/collection/List.kt
index dc28642bc2c6..d35e69e88e72 100644
--- a/services/permission/java/com/android/server/permission/access/collection/List.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/List.kt
@@ -49,18 +49,24 @@ inline fun <T> List<T>.noneIndexed(predicate: (Int, T) -> Boolean): Boolean {
return true
}
-inline fun <T> MutableList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> MutableList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, this[index])) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
-inline fun <T> MutableList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
+inline fun <T> MutableList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
+ var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, this[index])) {
removeAt(index)
+ isChanged = true
}
}
+ return isChanged
}
diff --git a/services/permission/java/com/android/server/permission/access/data/Package.kt b/services/permission/java/com/android/server/permission/access/data/Package.kt
deleted file mode 100644
index d6f98ab256cf..000000000000
--- a/services/permission/java/com/android/server/permission/access/data/Package.kt
+++ /dev/null
@@ -1,43 +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.server.permission.access.data
-
-import com.android.server.permission.access.external.AndroidPackage
-
-class Package(
- private val androidPackage: AndroidPackage
-) {
- val name: String
- get() = androidPackage.packageName
-
- val adoptPermissions: List<String>
- get() = androidPackage.adoptPermissions
-
- val appId: Int
- get() = androidPackage.appId
-
- val requestedPermissions: List<String>
- get() = androidPackage.requestedPermissions
-
- override fun equals(other: Any?): Boolean {
- throw NotImplementedError()
- }
-
- override fun hashCode(): Int {
- throw NotImplementedError()
- }
-}
diff --git a/services/permission/java/com/android/server/permission/access/external/KnownPackages.kt b/services/permission/java/com/android/server/permission/access/external/KnownPackages.kt
deleted file mode 100644
index 1239450c0963..000000000000
--- a/services/permission/java/com/android/server/permission/access/external/KnownPackages.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.permission.access.external
-
-class KnownPackages {
- companion object {
- const val PACKAGE_SYSTEM = 0
- const val PACKAGE_SETUP_WIZARD = 1
- const val PACKAGE_INSTALLER = 2
- const val PACKAGE_VERIFIER = 4
- const val PACKAGE_SYSTEM_TEXT_CLASSIFIER = 6
- const val PACKAGE_PERMISSION_CONTROLLER = 7
- const val PACKAGE_CONFIGURATOR = 10
- const val PACKAGE_INCIDENT_REPORT_APPROVER = 11
- const val PACKAGE_APP_PREDICTOR = 12
- const val PACKAGE_COMPANION = 15
- const val PACKAGE_RETAIL_DEMO = 16
- const val PACKAGE_RECENTS = 17
- }
-}
diff --git a/services/permission/java/com/android/server/permission/access/external/PackageState.kt b/services/permission/java/com/android/server/permission/access/external/PackageState.kt
deleted file mode 100644
index b81d7946f2e9..000000000000
--- a/services/permission/java/com/android/server/permission/access/external/PackageState.kt
+++ /dev/null
@@ -1,65 +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.server.permission.access.external
-
-import android.util.SparseArray
-
-interface PackageState {
- val androidPackage: AndroidPackage?
- val appId: Int
- val isSystem: Boolean
- val isUpdatedSystemApp: Boolean
- val packageName: String
- val userStates: SparseArray<PackageUserState>
- val hasSharedUser: Boolean
- val sharedUserAppId: Int
- val signingDetails: SigningDetails
-}
-
-interface AndroidPackage {
- val packageName: String
- val apexModuleName: String?
- val appId: Int
- val isPrivileged: Boolean
- val isOem: Boolean
- val isVendor: Boolean
- val isProduct: Boolean
- val isSystemExt: Boolean
- val targetSdkVersion: Int
- val adoptPermissions: List<String>
- val permissions: List<ParsedPermission>
- val permissionGroups: List<ParsedPermissionGroup>
- val requestedPermissions: List<String>
- val implicitPermissions: List<String>
-}
-
-interface ParsedPermission {
- val name: String
- val isTree: Boolean
- val packageName: String
- val isSignature: Boolean
- val protectionLevel: Int
-}
-
-interface ParsedPermissionGroup {
- val name: String
- val packageName: String
-}
-
-interface PackageUserState {
- val isInstantApp: Boolean
-}
diff --git a/services/permission/java/com/android/server/permission/access/external/SigningDetails.kt b/services/permission/java/com/android/server/permission/access/external/SigningDetails.kt
deleted file mode 100644
index 25917f993d4d..000000000000
--- a/services/permission/java/com/android/server/permission/access/external/SigningDetails.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.permission.access.external
-
-object SigningDetails {
- fun hasCommonSignerWithCapability(otherDetails: SigningDetails, flags: Int): Boolean {
- throw NotImplementedError()
- }
-
- fun hasAncestorOrSelf(oldDetails: SigningDetails): Boolean {
- throw NotImplementedError()
- }
-
- fun checkCapability(oldDetails: SigningDetails, flags: Int): Boolean {
- throw NotImplementedError()
- }
-
- fun hasAncestorOrSelfWithDigest(certDigests: Set<String>): Boolean {
- throw NotImplementedError()
- }
-
- class CertCapabilities {
- companion object {
- /** grant SIGNATURE permissions to pkgs with this cert */
- var PERMISSION = 4
- }
- }
-}
diff --git a/services/permission/java/com/android/server/permission/access/data/Permission.kt b/services/permission/java/com/android/server/permission/access/permission/Permission.kt
index 877f23b0e825..efa5bf3118d6 100644
--- a/services/permission/java/com/android/server/permission/access/data/Permission.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/Permission.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.permission.access.data
+package com.android.server.permission.access.permission
import android.content.pm.PermissionInfo
import com.android.server.permission.access.util.hasBits
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
index bb1a86c7b32d..1b055202af7c 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
@@ -27,6 +27,7 @@ object PermissionFlags {
// For the permissions that are implicit for the package
const val IMPLICIT = 1 shl 5
+ const val MASK_ALL = 0.inv()
const val MASK_GRANTED = INSTALL_GRANTED or PROTECTION_GRANTED or OTHER_GRANTED or ROLE_GRANTED
const val MASK_RUNTIME = OTHER_GRANTED or IMPLICIT
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index cc51866b4695..1e6996b02721 100644
--- a/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -33,8 +33,9 @@ import com.android.server.pm.permission.PermissionManagerServiceInterface
import com.android.server.permission.access.AccessCheckingService
import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.UidUri
-import com.android.server.permission.access.data.Permission
+import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.util.hasBits
+import com.android.server.pm.UserManagerService
import com.android.server.pm.permission.LegacyPermission
import com.android.server.pm.permission.LegacyPermissionSettings
import com.android.server.pm.permission.LegacyPermissionState
@@ -46,17 +47,24 @@ import java.io.PrintWriter
/**
* Modern implementation of [PermissionManagerServiceInterface].
*/
-class ModernPermissionManagerServiceImpl(
+class PermissionService(
private val service: AccessCheckingService
) : PermissionManagerServiceInterface {
private val policy =
service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as UidPermissionPolicy
- private val packageManagerInternal =
- LocalServices.getService(PackageManagerInternal::class.java)
+ private lateinit var packageManagerInternal: PackageManagerInternal
+ private lateinit var packageManagerLocal: PackageManagerLocal
+ private lateinit var userManagerService: UserManagerService
- private val packageManagerLocal =
- LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
+ private val mountedStorageVolumes = IndexedSet<String?>()
+
+ fun initialize() {
+ packageManagerInternal = LocalServices.getService(PackageManagerInternal::class.java)
+ packageManagerLocal =
+ LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
+ userManagerService = UserManagerService.getInstance()
+ }
override fun getAllPermissionGroups(flags: Int): List<PermissionGroupInfo> {
TODO("Not yet implemented")
@@ -351,6 +359,8 @@ class ModernPermissionManagerServiceImpl(
}
override fun readLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
+ // Package settings has been read when this method is called.
+ service.initialize()
TODO("Not yet implemented")
}
@@ -375,15 +385,18 @@ class ModernPermissionManagerServiceImpl(
}
override fun onUserCreated(userId: Int) {
- TODO("Not yet implemented")
+ service.onUserAdded(userId)
}
override fun onUserRemoved(userId: Int) {
- TODO("Not yet implemented")
+ service.onUserRemoved(userId)
}
override fun onStorageVolumeMounted(volumeUuid: String, fingerprintChanged: Boolean) {
- TODO("Not yet implemented")
+ service.onStorageVolumeMounted(volumeUuid, fingerprintChanged)
+ synchronized(mountedStorageVolumes) {
+ mountedStorageVolumes += volumeUuid
+ }
}
override fun onPackageAdded(
@@ -391,7 +404,18 @@ class ModernPermissionManagerServiceImpl(
isInstantApp: Boolean,
oldPackage: AndroidPackage?
) {
- TODO("Not yet implemented")
+ synchronized(mountedStorageVolumes) {
+ if (androidPackage.volumeUuid !in mountedStorageVolumes) {
+ // Wait for the storage volume to be mounted and batch the state mutation there.
+ return
+ }
+ }
+ service.onPackageAdded(androidPackage.packageName)
+ }
+
+ override fun onPackageRemoved(androidPackage: AndroidPackage) {
+ // This may not be a full removal so ignored - we'll figure out full removal in
+ // onPackageUninstalled().
}
override fun onPackageInstalled(
@@ -400,21 +424,37 @@ class ModernPermissionManagerServiceImpl(
params: PermissionManagerServiceInternal.PackageInstalledParams,
userId: Int
) {
- TODO("Not yet implemented")
+ synchronized(mountedStorageVolumes) {
+ if (androidPackage.volumeUuid !in mountedStorageVolumes) {
+ // Wait for the storage volume to be mounted and batch the state mutation there.
+ return
+ }
+ }
+ val userIds = if (userId == UserHandle.USER_ALL) {
+ userManagerService.userIdsIncludingPreCreated
+ } else {
+ intArrayOf(userId)
+ }
+ userIds.forEach { service.onPackageInstalled(androidPackage.packageName, params, it) }
}
override fun onPackageUninstalled(
packageName: String,
appId: Int,
androidPackage: AndroidPackage?,
- sharedUserPkgs: MutableList<AndroidPackage>,
+ sharedUserPkgs: List<AndroidPackage>,
userId: Int
) {
- TODO("Not yet implemented")
- }
-
- override fun onPackageRemoved(androidPackage: AndroidPackage) {
- TODO("Not yet implemented")
+ val userIds = if (userId == UserHandle.USER_ALL) {
+ userManagerService.userIdsIncludingPreCreated
+ } else {
+ intArrayOf(userId)
+ }
+ userIds.forEach { service.onPackageUninstalled(packageName, appId, it) }
+ val packageState = packageManagerInternal.packageStates[packageName]
+ if (packageState == null) {
+ service.onPackageRemoved(packageName, appId)
+ }
}
/**
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt
index 3489061c5bae..061933a13fb4 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt
@@ -22,7 +22,6 @@ import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.SystemState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.data.Permission
import com.android.server.permission.access.util.attribute
import com.android.server.permission.access.util.attributeInt
import com.android.server.permission.access.util.attributeIntHex
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
index e08192444d67..3d6d2ce34141 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
@@ -20,9 +20,11 @@ import android.Manifest
import android.content.pm.PackageManager
import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
+import android.content.pm.SigningDetails
import android.os.Build
import android.os.UserHandle
import android.util.Log
+import com.android.internal.os.RoSystemProperties
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
@@ -33,22 +35,24 @@ import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.SchemePolicy
import com.android.server.permission.access.SystemState
import com.android.server.permission.access.UidUri
-import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.data.Permission
-import com.android.server.permission.access.external.AndroidPackage
-import com.android.server.permission.access.external.CompatibilityPermissionInfo
-import com.android.server.permission.access.external.KnownPackages
-import com.android.server.permission.access.external.PackageInfoUtils
-import com.android.server.permission.access.external.PackageState
-import com.android.server.permission.access.external.RoSystemProperties
-import com.android.server.permission.access.external.SigningDetails
+import com.android.server.permission.access.util.andInv
import com.android.server.permission.access.util.hasAnyBit
import com.android.server.permission.access.util.hasBits
+import com.android.server.pm.KnownPackages
+import com.android.server.pm.parsing.PackageInfoUtils
+import com.android.server.pm.permission.CompatibilityPermissionInfo
+import com.android.server.pm.pkg.AndroidPackage
+import com.android.server.pm.pkg.PackageState
class UidPermissionPolicy : SchemePolicy() {
private val persistence = UidPermissionPersistence()
+ @Volatile
+ private var onPermissionFlagsChangedListeners =
+ IndexedListSet<OnPermissionFlagsChangedListener>()
+ private val onPermissionFlagsChangedListenersLock = Any()
+
override val subjectScheme: String
get() = UidUri.SCHEME
@@ -58,8 +62,7 @@ class UidPermissionPolicy : SchemePolicy() {
override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
subject as UidUri
`object` as PermissionUri
- return state.userStates[subject.userId]?.permissionFlags?.get(subject.appId)
- ?.get(`object`.permissionName) ?: 0
+ return getPermissionFlags(subject.appId, subject.userId, `object`.permissionName)
}
override fun MutateStateScope.setDecision(
@@ -69,26 +72,22 @@ class UidPermissionPolicy : SchemePolicy() {
) {
subject as UidUri
`object` as PermissionUri
- val uidFlags = newState.userStates.getOrPut(subject.userId) { UserState() }
- .permissionFlags.getOrPut(subject.appId) { IndexedMap() }
- uidFlags[`object`.permissionName] = decision
+ setPermissionFlags(subject.appId, subject.userId, `object`.permissionName, decision)
}
override fun MutateStateScope.onUserAdded(userId: Int) {
- newState.systemState.packageStates.forEachValueIndexed { _, packageState ->
- evaluateAllPermissionStatesForPackageAndUser(packageState, null, userId)
+ newState.systemState.packageStates.forEach { (_, packageState) ->
+ evaluateAllPermissionStatesForPackageAndUser(packageState, userId, null)
grantImplicitPermissions(packageState, userId)
}
}
- override fun MutateStateScope.onAppIdAdded(appId: Int) {
- newState.userStates.forEachIndexed { _, _, userState ->
- userState.permissionFlags.getOrPut(appId) { IndexedMap() }
- }
- }
-
override fun MutateStateScope.onAppIdRemoved(appId: Int) {
- newState.userStates.forEachIndexed { _, _, userState -> userState.permissionFlags -= appId }
+ newState.userStates.forEachValueIndexed { _, userState ->
+ userState.uidPermissionFlags -= appId
+ userState.requestWrite()
+ // Skip notifying the change listeners since the app ID no longer exists.
+ }
}
override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
@@ -97,7 +96,7 @@ class UidPermissionPolicy : SchemePolicy() {
addPermissionGroups(packageState)
addPermissions(packageState, changedPermissionNames)
// TODO: revokeStoragePermissionsIfScopeExpandedInternal()
- trimPermissions(packageState.packageName)
+ trimPermissions(packageState.packageName, changedPermissionNames)
changedPermissionNames.forEachIndexed { _, permissionName ->
evaluatePermissionStateForAllPackages(permissionName, packageState)
}
@@ -121,22 +120,23 @@ class UidPermissionPolicy : SchemePolicy() {
if (!canAdoptPermissions(packageName, originalPackageName)) {
return@forEachIndexed
}
- newState.systemState.permissions.let { permissions ->
- permissions.forEachIndexed permissions@ {
- permissionIndex, permissionName, oldPermission ->
- if (oldPermission.packageName != originalPackageName) {
- return@permissions
- }
- @Suppress("DEPRECATION")
- val newPermissionInfo = PermissionInfo().apply {
- name = oldPermission.permissionInfo.name
- this.packageName = packageName
- protectionLevel = oldPermission.permissionInfo.protectionLevel
- }
- val newPermission = Permission(newPermissionInfo, false, oldPermission.type, 0)
- changedPermissionNames += permissionName
- permissions.setValueAt(permissionIndex, newPermission)
+ val systemState = newState.systemState
+ val permissions = systemState.permissions
+ permissions.forEachIndexed permissions@ {
+ permissionIndex, permissionName, oldPermission ->
+ if (oldPermission.packageName != originalPackageName) {
+ return@permissions
+ }
+ @Suppress("DEPRECATION")
+ val newPermissionInfo = PermissionInfo().apply {
+ name = oldPermission.permissionInfo.name
+ this.packageName = packageName
+ protectionLevel = oldPermission.permissionInfo.protectionLevel
}
+ val newPermission = Permission(newPermissionInfo, false, oldPermission.type, 0)
+ permissions.setValueAt(permissionIndex, newPermission)
+ systemState.requestWrite()
+ changedPermissionNames += permissionName
}
}
}
@@ -179,7 +179,7 @@ class UidPermissionPolicy : SchemePolicy() {
packageState.androidPackage!!.permissionGroups.forEachIndexed { _, parsedPermissionGroup ->
val newPermissionGroup = PackageInfoUtils.generatePermissionGroupInfo(
parsedPermissionGroup, PackageManager.GET_META_DATA.toLong()
- )
+ )!!
// TODO: Clear permission state on group take-over?
val permissionGroupName = newPermissionGroup.name
val oldPermissionGroup = newState.systemState.permissionGroups[permissionGroupName]
@@ -211,13 +211,14 @@ class UidPermissionPolicy : SchemePolicy() {
// }
val newPermissionInfo = PackageInfoUtils.generatePermissionInfo(
parsedPermission, PackageManager.GET_META_DATA.toLong()
- )
+ )!!
// TODO: newPermissionInfo.flags |= PermissionInfo.FLAG_INSTALLED
+ val systemState = newState.systemState
val permissionName = newPermissionInfo.name
val oldPermission = if (parsedPermission.isTree) {
- newState.systemState.permissionTrees[permissionName]
+ systemState.permissionTrees[permissionName]
} else {
- newState.systemState.permissions[permissionName]
+ systemState.permissions[permissionName]
}
// Different from the old implementation, which may add an (incomplete) signature
// permission inside another package's permission tree, we now consistently ignore such
@@ -247,19 +248,18 @@ class UidPermissionPolicy : SchemePolicy() {
if (oldPermission.type == Permission.TYPE_CONFIG && !oldPermission.isReconciled) {
// It's a config permission and has no owner, take ownership now.
Permission(newPermissionInfo, true, Permission.TYPE_CONFIG, packageState.appId)
- } else if (newState.systemState.packageStates[oldPackageName]?.isSystem != true) {
+ } else if (systemState.packageStates[oldPackageName]?.isSystem != true) {
Log.w(
LOG_TAG, "Overriding permission $permissionName with new declaration in" +
" system package $newPackageName: originally declared in another" +
" package $oldPackageName"
)
// Remove permission state on owner change.
- newState.userStates.forEachValueIndexed { _, userState ->
- userState.permissionFlags.forEachValueIndexed { _, permissionFlags ->
- permissionFlags -= newPermissionInfo.name
+ systemState.userIds.forEachIndexed { _, userId ->
+ systemState.appIds.forEachKeyIndexed { _, appId ->
+ setPermissionFlags(appId, userId, permissionName, 0)
}
}
- // TODO: Notify re-evaluation of this permission.
Permission(
newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId
)
@@ -278,23 +278,28 @@ class UidPermissionPolicy : SchemePolicy() {
Permission(newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId)
}
- changedPermissionNames += permissionName
if (parsedPermission.isTree) {
- newState.systemState.permissionTrees[permissionName] = newPermission
+ systemState.permissionTrees[permissionName] = newPermission
} else {
- newState.systemState.permissions[permissionName] = newPermission
+ systemState.permissions[permissionName] = newPermission
}
+ systemState.requestWrite()
+ changedPermissionNames += permissionName
}
}
- private fun MutateStateScope.trimPermissions(packageName: String) {
- val packageState = newState.systemState.packageStates[packageName]
+ private fun MutateStateScope.trimPermissions(
+ packageName: String,
+ changedPermissionNames: IndexedSet<String>
+ ) {
+ val systemState = newState.systemState
+ val packageState = systemState.packageStates[packageName]
val androidPackage = packageState?.androidPackage
if (packageState != null && androidPackage == null) {
return
}
- newState.systemState.permissionTrees.removeAllIndexed {
+ val isPermissionTreeRemoved = systemState.permissionTrees.removeAllIndexed {
_, permissionTreeName, permissionTree ->
permissionTree.packageName == packageName && (
packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
@@ -302,26 +307,30 @@ class UidPermissionPolicy : SchemePolicy() {
}
)
}
+ if (isPermissionTreeRemoved) {
+ systemState.requestWrite()
+ }
- newState.systemState.permissions.removeAllIndexed { i, permissionName, permission ->
+ systemState.permissions.removeAllIndexed { permissionIndex, permissionName, permission ->
val updatedPermission = updatePermissionIfDynamic(permission)
- newState.systemState.permissions.setValueAt(i, updatedPermission)
+ newState.systemState.permissions.setValueAt(permissionIndex, updatedPermission)
if (updatedPermission.packageName == packageName && (
packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
!it.isTree && it.name == permissionName
}
)) {
- if (!isPermissionDeclaredByDisabledSystemPackage(permission)) {
- newState.userStates.forEachIndexed { _, userId, userState ->
- userState.permissionFlags.forEachKeyIndexed { _, appId ->
- setPermissionFlags(
- appId, permissionName, getPermissionFlags(
- appId, permissionName, userId
- ) and PermissionFlags.INSTALL_REVOKED, userId
- )
- }
+ // Different from the old implementation where we keep the permission state if the
+ // permission is declared by a disabled system package (ag/15189282), we now
+ // shouldn't be notified when the updated system package is removed but the disabled
+ // system package isn't re-enabled yet, so we don't need to maintain that brittle
+ // special case either.
+ systemState.userIds.forEachIndexed { _, userId ->
+ systemState.appIds.forEachKeyIndexed { _, appId ->
+ setPermissionFlags(appId, userId, permissionName, 0)
}
}
+ changedPermissionNames += permissionName
+ systemState.requestWrite()
true
} else {
false
@@ -329,16 +338,6 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
- private fun MutateStateScope.isPermissionDeclaredByDisabledSystemPackage(
- permission: Permission
- ): Boolean {
- val disabledSystemPackage = newState.systemState
- .disabledSystemPackageStates[permission.packageName]?.androidPackage ?: return false
- return disabledSystemPackage.permissions.anyIndexed { _, it ->
- it.name == permission.name && it.protectionLevel == permission.protectionLevel
- }
- }
-
private fun MutateStateScope.updatePermissionIfDynamic(permission: Permission): Permission {
if (!permission.isDynamic) {
return permission
@@ -368,11 +367,14 @@ class UidPermissionPolicy : SchemePolicy() {
permissionName: String,
installedPackageState: PackageState?
) {
- newState.systemState.userIds.forEachIndexed { _, userId ->
- oldState.userStates[userId]?.permissionFlags?.forEachIndexed {
- _, appId, permissionFlags ->
- if (permissionName in permissionFlags) {
- evaluatePermissionState(appId, permissionName, installedPackageState, userId)
+ val systemState = newState.systemState
+ systemState.userIds.forEachIndexed { _, userId ->
+ systemState.appIds.forEachKeyIndexed { _, appId ->
+ val isPermissionRequested = anyPackageInAppId(appId) { packageState ->
+ permissionName in packageState.androidPackage!!.requestedPermissions
+ }
+ if (isPermissionRequested) {
+ evaluatePermissionState(appId, userId, permissionName, installedPackageState)
}
}
}
@@ -384,28 +386,28 @@ class UidPermissionPolicy : SchemePolicy() {
) {
newState.systemState.userIds.forEachIndexed { _, userId ->
evaluateAllPermissionStatesForPackageAndUser(
- packageState, installedPackageState, userId
+ packageState, userId, installedPackageState
)
}
}
private fun MutateStateScope.evaluateAllPermissionStatesForPackageAndUser(
packageState: PackageState,
- installedPackageState: PackageState?,
- userId: Int
+ userId: Int,
+ installedPackageState: PackageState?
) {
packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, permissionName ->
evaluatePermissionState(
- packageState.appId, permissionName, installedPackageState, userId
+ packageState.appId, userId, permissionName, installedPackageState
)
}
}
private fun MutateStateScope.evaluatePermissionState(
appId: Int,
+ userId: Int,
permissionName: String,
- installedPackageState: PackageState?,
- userId: Int
+ installedPackageState: PackageState?
) {
val packageNames = newState.systemState.appIds[appId]
val hasMissingPackage = packageNames.anyIndexed { _, packageName ->
@@ -416,7 +418,7 @@ class UidPermissionPolicy : SchemePolicy() {
return
}
val permission = newState.systemState.permissions[permissionName] ?: return
- val oldFlags = getPermissionFlags(appId, permissionName, userId)
+ val oldFlags = getPermissionFlags(appId, userId, permissionName)
if (permission.isNormal) {
val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
if (!wasGranted) {
@@ -438,7 +440,7 @@ class UidPermissionPolicy : SchemePolicy() {
} else {
PermissionFlags.INSTALL_REVOKED
}
- setPermissionFlags(appId, permissionName, newFlags, userId)
+ setPermissionFlags(appId, userId, permissionName, newFlags)
}
} else if (permission.isSignature || permission.isInternal) {
val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
@@ -477,7 +479,7 @@ class UidPermissionPolicy : SchemePolicy() {
if (permission.isRole) {
newFlags = newFlags or (oldFlags and PermissionFlags.ROLE_GRANTED)
}
- setPermissionFlags(appId, permissionName, newFlags, userId)
+ setPermissionFlags(appId, userId, permissionName, newFlags)
} else if (permission.isRuntime) {
// TODO: add runtime permissions
} else {
@@ -503,7 +505,7 @@ class UidPermissionPolicy : SchemePolicy() {
}
// Explicitly check against the old state to determine if this permission is new.
val isNewPermission = getPermissionFlags(
- appId, implicitPermissionName, userId, oldState
+ appId, userId, implicitPermissionName, oldState
) == 0
if (!isNewPermission) {
return@implicitPermissions
@@ -516,7 +518,7 @@ class UidPermissionPolicy : SchemePolicy() {
checkNotNull(sourcePermission) {
"Unknown source permission $sourcePermissionName in split permissions"
}
- val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId)
+ val sourceFlags = getPermissionFlags(appId, userId, sourcePermissionName)
val isSourceGranted = sourceFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isNewGranted = newFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isGrantingNewFromRevoke = isSourceGranted && !isNewGranted
@@ -531,27 +533,10 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
newFlags = newFlags or PermissionFlags.IMPLICIT
- setPermissionFlags(appId, implicitPermissionName, newFlags, userId)
+ setPermissionFlags(appId, userId, implicitPermissionName, newFlags)
}
}
- private fun MutateStateScope.getPermissionFlags(
- appId: Int,
- permissionName: String,
- userId: Int,
- state: AccessState = newState
- ): Int = state.userStates[userId].permissionFlags[appId].getWithDefault(permissionName, 0)
-
- private fun MutateStateScope.setPermissionFlags(
- appId: Int,
- permissionName: String,
- flags: Int,
- userId: Int
- ) {
- newState.userStates[userId].permissionFlags[appId]!!
- .putWithDefault(permissionName, flags, 0)
- }
-
private fun isCompatibilityPermissionForPackage(
androidPackage: AndroidPackage,
permissionName: String
@@ -573,23 +558,24 @@ class UidPermissionPolicy : SchemePolicy() {
packageState: PackageState,
permission: Permission
): Boolean {
- // check if the package is allow to use this signature permission. A package is allowed to
- // use a signature permission if:
- // - it has the same set of signing certificates as the source package
- // - or its signing certificate was rotated from the source package's certificate
- // - or its signing certificate is a previous signing certificate of the defining
- // package, and the defining package still trusts the old certificate for permissions
- // - or it shares a common signing certificate in its lineage with the defining package,
- // and the defining package still trusts the old certificate for permissions
- // - or it shares the above relationships with the system package
+ // Check if the package is allowed to use this signature permission. A package is allowed
+ // to use a signature permission if:
+ // - it has the same set of signing certificates as the source package
+ // - or its signing certificate was rotated from the source package's certificate
+ // - or its signing certificate is a previous signing certificate of the defining
+ // package, and the defining package still trusts the old certificate for permissions
+ // - or it shares a common signing certificate in its lineage with the defining package,
+ // and the defining package still trusts the old certificate for permissions
+ // - or it shares the above relationships with the system package
+ val packageSigningDetails = packageState.androidPackage!!.signingDetails
val sourceSigningDetails = newState.systemState
- .packageStates[permission.packageName]?.signingDetails
+ .packageStates[permission.packageName]?.androidPackage?.signingDetails
val platformSigningDetails = newState.systemState
- .packageStates[PLATFORM_PACKAGE_NAME]!!.signingDetails
- return sourceSigningDetails?.hasCommonSignerWithCapability(packageState.signingDetails,
+ .packageStates[PLATFORM_PACKAGE_NAME]!!.androidPackage!!.signingDetails
+ return sourceSigningDetails?.hasCommonSignerWithCapability(packageSigningDetails,
SigningDetails.CertCapabilities.PERMISSION) == true ||
- packageState.signingDetails.hasAncestorOrSelf(platformSigningDetails) ||
- platformSigningDetails.checkCapability(packageState.signingDetails,
+ packageSigningDetails.hasAncestorOrSelf(platformSigningDetails) ||
+ platformSigningDetails.checkCapability(packageSigningDetails,
SigningDetails.CertCapabilities.PERMISSION)
}
@@ -629,7 +615,10 @@ class UidPermissionPolicy : SchemePolicy() {
androidPackage: AndroidPackage,
permissionName: String
): Boolean {
- val apexModuleName = androidPackage.apexModuleName
+ // TODO(b/261913353): STOPSHIP: Add AndroidPackage.apexModuleName. The below is only for
+ // passing compilation but won't actually work.
+ //val apexModuleName = androidPackage.apexModuleName
+ val apexModuleName = androidPackage.packageName
val systemState = newState.systemState
val packageName = androidPackage.packageName
val permissionNames = when {
@@ -657,7 +646,10 @@ class UidPermissionPolicy : SchemePolicy() {
): Boolean {
// Different from the previous implementation, which may incorrectly use the APEX package
// name, we now use the APEX module name to be consistent with the allowlist.
- val apexModuleName = androidPackage.apexModuleName
+ // TODO(b/261913353): STOPSHIP: Add AndroidPackage.apexModuleName. The below is only for
+ // passing compilation but won't actually work.
+ //val apexModuleName = androidPackage.apexModuleName
+ val apexModuleName = androidPackage.packageName
val systemState = newState.systemState
val packageName = androidPackage.packageName
val permissionNames = when {
@@ -741,7 +733,7 @@ class UidPermissionPolicy : SchemePolicy() {
return true
}
if (permission.isKnownSigner &&
- packageState.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)) {
+ androidPackage.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)) {
// If the permission is to be granted to a known signer then check if any of this
// app's signing certificates are in the trusted certificate digest Set.
return true
@@ -840,8 +832,11 @@ class UidPermissionPolicy : SchemePolicy() {
return uid == ownerUid
}
- override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
- // TODO
+ override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
+ // TODO: STOPSHIP: Remove this check or at least turn into logging.
+ check(packageName !in newState.systemState.disabledSystemPackageStates) {
+ "Package $packageName reported as removed before disabled system package is enabled"
+ }
}
override fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {
@@ -858,6 +853,76 @@ class UidPermissionPolicy : SchemePolicy() {
fun GetStateScope.getPermission(permissionName: String): Permission? =
state.systemState.permissions[permissionName]
+ fun GetStateScope.getPermissionFlags(
+ appId: Int,
+ userId: Int,
+ permissionName: String
+ ): Int = getPermissionFlags(state, appId, userId, permissionName)
+
+ private fun MutateStateScope.getPermissionFlags(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ state: AccessState = newState
+ ): Int = getPermissionFlags(state, appId, userId, permissionName)
+
+ private fun getPermissionFlags(
+ state: AccessState,
+ appId: Int,
+ userId: Int,
+ permissionName: String
+ ): Int = state.userStates[userId].uidPermissionFlags[appId].getWithDefault(permissionName, 0)
+
+ fun MutateStateScope.setPermissionFlags(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ flags: Int
+ ): Boolean =
+ updatePermissionFlags(appId, userId, permissionName, PermissionFlags.MASK_ALL, flags)
+
+ fun MutateStateScope.updatePermissionFlags(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ flagMask: Int,
+ flagValues: Int
+ ): Boolean {
+ val userState = newState.userStates[userId]
+ val uidPermissionFlags = userState.uidPermissionFlags
+ var permissionFlags = uidPermissionFlags[appId]
+ val oldFlags = permissionFlags.getWithDefault(permissionName, 0)
+ val newFlags = (oldFlags andInv flagMask) or flagValues
+ if (oldFlags == newFlags) {
+ return false
+ }
+ if (permissionFlags == null) {
+ permissionFlags = IndexedMap()
+ uidPermissionFlags[appId] = permissionFlags
+ }
+ permissionFlags.putWithDefault(permissionName, newFlags, 0)
+ if (permissionFlags.isEmpty()) {
+ uidPermissionFlags -= appId
+ }
+ userState.requestWrite()
+ onPermissionFlagsChangedListeners.forEachIndexed { _, it ->
+ it.onPermissionFlagsChanged(appId, userId, permissionName, oldFlags, newFlags)
+ }
+ return true
+ }
+
+ fun addOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
+ synchronized(onPermissionFlagsChangedListenersLock) {
+ onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners + listener
+ }
+ }
+
+ fun removeOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
+ synchronized(onPermissionFlagsChangedListenersLock) {
+ onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners - listener
+ }
+ }
+
companion object {
private val LOG_TAG = UidPermissionPolicy::class.java.simpleName
@@ -872,4 +937,14 @@ class UidPermissionPolicy : SchemePolicy() {
Manifest.permission.READ_MEDIA_VIDEO,
)
}
+
+ fun interface OnPermissionFlagsChangedListener {
+ fun onPermissionFlagsChanged(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ oldFlags: Int,
+ newFlags: Int
+ )
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index b9615f6b3771..d79c4d8d83af 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -50,6 +50,7 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.IApplicationThread;
+import android.app.ReceiverInfo;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
@@ -62,6 +63,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
+import android.content.res.CompatibilityInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.DeadObjectException;
@@ -262,6 +264,7 @@ public class BroadcastQueueTest {
return res;
}).when(mAms).startProcessLocked(any(), any(), anyBoolean(), anyInt(),
any(), anyInt(), anyBoolean(), anyBoolean());
+
doAnswer((invocation) -> {
final String processName = invocation.getArgument(0);
final int uid = invocation.getArgument(1);
@@ -295,12 +298,16 @@ public class BroadcastQueueTest {
};
if (mImpl == Impl.DEFAULT) {
- mQueue = new BroadcastQueueImpl(mAms, mHandlerThread.getThreadHandler(), TAG,
+ var q = new BroadcastQueueImpl(mAms, mHandlerThread.getThreadHandler(), TAG,
constants, emptySkipPolicy, emptyHistory, false,
ProcessList.SCHED_GROUP_DEFAULT);
+ q.mReceiverBatch.mDeepReceiverCopy = true;
+ mQueue = q;
} else if (mImpl == Impl.MODERN) {
- mQueue = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(),
+ var q = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(),
constants, constants, emptySkipPolicy, emptyHistory);
+ q.mReceiverBatch.mDeepReceiverCopy = true;
+ mQueue = q;
} else {
throw new UnsupportedOperationException();
}
@@ -398,6 +405,43 @@ public class BroadcastQueueTest {
UnaryOperator.identity());
}
+ private void doRegisteredReceiver(ProcessRecord r, boolean wedge, boolean abort,
+ UnaryOperator<Bundle> extrasOperator, ReceiverInfo info) {
+ final Intent intent = info.intent;
+ final Bundle extras = info.extras;
+ final boolean ordered = info.ordered;
+ mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent));
+ if (!wedge && ordered) {
+ assertTrue(r.mReceivers.numberOfCurReceivers() > 0);
+ assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED,
+ mQueue.getPreferredSchedulingGroupLocked(r));
+ mHandlerThread.getThreadHandler().post(() -> {
+ synchronized (mAms) {
+ mQueue.finishReceiverLocked(r, Activity.RESULT_OK,
+ null, extrasOperator.apply(extras), abort, false);
+ }
+ });
+ }
+ }
+
+ private void doManifestReceiver(ProcessRecord r, boolean wedge, boolean abort,
+ UnaryOperator<Bundle> extrasOperator, ReceiverInfo info) {
+ final Intent intent = info.intent;
+ final Bundle extras = info.extras;
+ mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent));
+ if (!wedge) {
+ assertTrue(r.mReceivers.numberOfCurReceivers() > 0);
+ assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED,
+ mQueue.getPreferredSchedulingGroupLocked(r));
+ mHandlerThread.getThreadHandler().post(() -> {
+ synchronized (mAms) {
+ mQueue.finishReceiverLocked(r, Activity.RESULT_OK, null,
+ extrasOperator.apply(extras), abort, false);
+ }
+ });
+ }
+ }
+
private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai, String processName,
ProcessBehavior behavior, UnaryOperator<Bundle> extrasOperator) throws Exception {
final boolean wedge = (behavior == ProcessBehavior.WEDGE);
@@ -441,47 +485,22 @@ public class BroadcastQueueTest {
if (dead) return r;
doAnswer((invocation) -> {
- Log.v(TAG, "Intercepting scheduleReceiver() for "
+ Log.v(TAG, "Intercepting scheduleReceiverList() for "
+ Arrays.toString(invocation.getArguments()));
- final Intent intent = invocation.getArgument(0);
- final Bundle extras = invocation.getArgument(5);
- mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent));
- if (!wedge) {
- assertTrue(r.mReceivers.numberOfCurReceivers() > 0);
- assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED,
- mQueue.getPreferredSchedulingGroupLocked(r));
- mHandlerThread.getThreadHandler().post(() -> {
- synchronized (mAms) {
- mQueue.finishReceiverLocked(r, Activity.RESULT_OK, null,
- extrasOperator.apply(extras), abort, false);
- }
- });
- }
- return null;
- }).when(thread).scheduleReceiver(any(), any(), any(), anyInt(), any(), any(), anyBoolean(),
- anyInt(), anyInt());
-
- doAnswer((invocation) -> {
- Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for "
- + Arrays.toString(invocation.getArguments()));
- final Intent intent = invocation.getArgument(1);
- final Bundle extras = invocation.getArgument(4);
- final boolean ordered = invocation.getArgument(5);
- mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent));
- if (!wedge && ordered) {
- assertTrue(r.mReceivers.numberOfCurReceivers() > 0);
- assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED,
- mQueue.getPreferredSchedulingGroupLocked(r));
- mHandlerThread.getThreadHandler().post(() -> {
- synchronized (mAms) {
- mQueue.finishReceiverLocked(r, Activity.RESULT_OK,
- null, extrasOperator.apply(extras), abort, false);
- }
- });
+ final List<ReceiverInfo> data = invocation.getArgument(0);
+ for (int i = 0; i < data.size(); i++) {
+ ReceiverInfo info = data.get(i);
+ // The logic here mimics the logic in ActivityThread: elements of the list are
+ // forwarded to a handler for manifest receivers or to a handler for registered
+ // receivers.
+ if (info.registered) {
+ doRegisteredReceiver(r, wedge, abort, extrasOperator, info);
+ } else {
+ doManifestReceiver(r, wedge, abort, extrasOperator, info);
+ }
}
return null;
- }).when(thread).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(),
- anyBoolean(), anyBoolean(), anyInt(), anyInt());
+ }).when(thread).scheduleReceiverList(any());
return r;
}
@@ -623,6 +642,123 @@ public class BroadcastQueueTest {
};
}
+ private static <T> boolean matchElement(T a, T b) {
+ return a == null || a.equals(b);
+ }
+ private static <T> boolean matchObject(ArgumentMatcher<T> m, T b) {
+ return m == null || m.matches(b);
+ }
+
+ /**
+ * Create an ArgumentMatcher for a manifest receiver. The parameters are in the order of
+ * {@link IApplicationThread#scheduleReceiver} but the names correspond to the field names in
+ * {@link ReceiverInfo}. For every parameter, a null means "don't care".
+ */
+ private ArgumentMatcher<ReceiverInfo> manifestReceiverMatcher(
+ ArgumentMatcher<Intent> intent,
+ ArgumentMatcher<ActivityInfo> activityInfo,
+ ArgumentMatcher<CompatibilityInfo> compatInfo,
+ Integer resultCode,
+ ArgumentMatcher<String> data,
+ ArgumentMatcher<Bundle> extras,
+ Boolean sync,
+ Integer sendingUser,
+ Integer processState) {
+ return (test) -> {
+ return test.registered == false
+ && matchObject(intent, test.intent)
+ && matchObject(activityInfo, test.activityInfo)
+ && matchObject(compatInfo, test.compatInfo)
+ && matchElement(resultCode, test.resultCode)
+ && matchObject(data, test.data)
+ && matchObject(extras, test.extras)
+ && matchElement(sync, test.sync)
+ && matchElement(sendingUser, test.sendingUser)
+ && matchElement(processState, test.processState);
+ };
+ }
+
+
+ /**
+ * Create an argument suitable for the verify() mock methods, when the goal is to find a call
+ * containing a manifest receiver.
+ */
+ private List<ReceiverInfo> manifestReceiver(
+ ArgumentMatcher<Intent> intent,
+ ArgumentMatcher<ActivityInfo> activityInfo,
+ ArgumentMatcher<CompatibilityInfo> compatInfo,
+ Integer resultCode,
+ ArgumentMatcher<String> data,
+ ArgumentMatcher<Bundle> extras,
+ Boolean sync,
+ Integer sendingUser,
+ Integer processState) {
+ return argThat(receiverList(manifestReceiverMatcher(intent, activityInfo, compatInfo,
+ resultCode, data, extras, sync, sendingUser, processState)));
+ }
+
+ /**
+ * Create an ArgumentMatcher for a registered receiver. The parameters are in the order of
+ * {@link IApplicationThread#scheduleRegisteredReceiver} but the names correspond to the field
+ * names in {@link ReceiverInfo}. For every parameter, a null means "don't care".
+ */
+ private ArgumentMatcher<ReceiverInfo> registeredReceiverMatcher(
+ ArgumentMatcher<IIntentReceiver> receiver,
+ ArgumentMatcher<Intent> intent,
+ Integer resultCode,
+ ArgumentMatcher<String> data,
+ ArgumentMatcher<Bundle> extras,
+ Boolean ordered,
+ Boolean sticky,
+ Integer sendingUser,
+ Integer processState) {
+ return (test) -> {
+ return test.registered == true
+ && matchObject(receiver, test.receiver)
+ && matchObject(intent, test.intent)
+ && matchElement(resultCode, test.resultCode)
+ && matchObject(data, test.data)
+ && matchObject(extras, test.extras)
+ && matchElement(ordered, test.ordered)
+ && matchElement(sticky, test.sticky)
+ && matchElement(sendingUser, test.sendingUser)
+ && matchElement(processState, test.processState);
+ };
+ }
+
+ /**
+ * Create an argument suitable for the verify() mock methods, when the goal is to find a call
+ * containing a registered receiver.
+ */
+ private List<ReceiverInfo> registeredReceiver(
+ ArgumentMatcher<IIntentReceiver> receiver,
+ ArgumentMatcher<Intent> intent,
+ Integer resultCode,
+ ArgumentMatcher<String> data,
+ ArgumentMatcher<Bundle> extras,
+ Boolean ordered,
+ Boolean sticky,
+ Integer sendingUser,
+ Integer processState) {
+ return argThat(receiverList(registeredReceiverMatcher(receiver, intent, resultCode,
+ data, extras, ordered, sticky, sendingUser, processState)));
+ }
+
+ /**
+ * Apply a matcher to every element in a ReceiverInfo list.
+ */
+ private ArgumentMatcher<List<ReceiverInfo>> receiverList(ArgumentMatcher<ReceiverInfo> a) {
+ return (test) -> {
+ for (int i = 0; i < test.size(); i++) {
+ ReceiverInfo r = test.get(i);
+ if (a.matches(r)) {
+ return true;
+ }
+ }
+ return false;
+ };
+ }
+
private ArgumentMatcher<Bundle> bundleEquals(Bundle bundle) {
return (test) -> {
// TODO: check values in addition to keys
@@ -654,26 +790,27 @@ public class BroadcastQueueTest {
}
private void verifyScheduleReceiver(VerificationMode mode, ProcessRecord app, Intent intent,
- int userId) throws Exception {
- verify(app.getThread(), mode).scheduleReceiver(
- argThat(filterEqualsIgnoringComponent(intent)), any(), any(), anyInt(), any(),
- any(), eq(false), eq(userId), anyInt());
- }
-
- private void verifyScheduleReceiver(VerificationMode mode, ProcessRecord app, Intent intent,
ComponentName component) throws Exception {
final Intent targetedIntent = new Intent(intent);
targetedIntent.setComponent(component);
- verify(app.getThread(), mode).scheduleReceiver(
- argThat(filterEquals(targetedIntent)), any(), any(), anyInt(), any(),
- any(), eq(false), eq(UserHandle.USER_SYSTEM), anyInt());
+ verify(app.getThread(), mode).scheduleReceiverList(
+ manifestReceiver(filterEquals(targetedIntent),
+ null, null, null, null, null, null, UserHandle.USER_SYSTEM, null));
+ }
+
+ private void verifyScheduleReceiver(VerificationMode mode, ProcessRecord app,
+ Intent intent, int userId) throws Exception {
+ verify(app.getThread(), mode).scheduleReceiverList(
+ manifestReceiver(filterEqualsIgnoringComponent(intent),
+ null, null, null, null, null, null, userId, null));
}
- private void verifyScheduleRegisteredReceiver(ProcessRecord app, Intent intent)
+ private void verifyScheduleRegisteredReceiver(ProcessRecord app,
+ Intent intent)
throws Exception {
- verify(app.getThread()).scheduleRegisteredReceiver(any(),
- argThat(filterEqualsIgnoringComponent(intent)), anyInt(), any(), any(),
- anyBoolean(), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+ verify(app.getThread()).scheduleReceiverList(
+ registeredReceiver(null, filterEqualsIgnoringComponent(intent),
+ null, null, null, null, null, UserHandle.USER_SYSTEM, null));
}
static final int USER_GUEST = 11;
@@ -1237,23 +1374,24 @@ public class BroadcastQueueTest {
final InOrder inOrder = inOrder(greenThread, blueThread, yellowThread, redThread);
final Bundle expectedExtras = new Bundle();
expectedExtras.putBoolean(PACKAGE_RED, true);
- inOrder.verify(greenThread).scheduleReceiver(
- argThat(filterEqualsIgnoringComponent(airplane)), any(), any(),
- eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), eq(true),
- eq(UserHandle.USER_SYSTEM), anyInt());
- inOrder.verify(blueThread).scheduleReceiver(
- argThat(filterEqualsIgnoringComponent(airplane)), any(), any(),
- eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), eq(true),
- eq(UserHandle.USER_SYSTEM), anyInt());
+ inOrder.verify(greenThread).scheduleReceiverList(manifestReceiver(
+ filterEqualsIgnoringComponent(airplane), null, null,
+ Activity.RESULT_OK, null, bundleEquals(expectedExtras), true,
+ UserHandle.USER_SYSTEM, null));
+ inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver(
+ filterEqualsIgnoringComponent(airplane), null, null,
+ Activity.RESULT_OK, null, bundleEquals(expectedExtras), true,
+ UserHandle.USER_SYSTEM, null));
expectedExtras.putBoolean(PACKAGE_BLUE, true);
- inOrder.verify(yellowThread).scheduleReceiver(
- argThat(filterEqualsIgnoringComponent(airplane)), any(), any(),
- eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), eq(true),
- eq(UserHandle.USER_SYSTEM), anyInt());
+ inOrder.verify(yellowThread).scheduleReceiverList(manifestReceiver(
+ filterEqualsIgnoringComponent(airplane), null, null,
+ Activity.RESULT_OK, null, bundleEquals(expectedExtras), true,
+ UserHandle.USER_SYSTEM, null));
expectedExtras.putBoolean(PACKAGE_YELLOW, true);
- inOrder.verify(redThread).scheduleRegisteredReceiver(any(), argThat(filterEquals(airplane)),
- eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), eq(false),
- anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+ inOrder.verify(redThread).scheduleReceiverList(registeredReceiver(
+ null, filterEquals(airplane),
+ Activity.RESULT_OK, null, bundleEquals(expectedExtras), false,
+ null, UserHandle.USER_SYSTEM, null));
// Finally, verify that we thawed the final receiver
verify(mAms.mOomAdjuster.mCachedAppOptimizer).unfreezeTemporarily(eq(callerApp),
@@ -1316,22 +1454,24 @@ public class BroadcastQueueTest {
// have invoked or skipped the second receiver depending on the intent
// flag policy; we always deliver to final receiver regardless of abort
final InOrder inOrder = inOrder(greenThread, blueThread, redThread);
- inOrder.verify(greenThread).scheduleReceiver(
- argThat(filterEqualsIgnoringComponent(intent)), any(), any(),
- eq(Activity.RESULT_OK), any(), any(), eq(true), eq(UserHandle.USER_SYSTEM),
- anyInt());
+ inOrder.verify(greenThread).scheduleReceiverList(manifestReceiver(
+ filterEqualsIgnoringComponent(intent), null, null,
+ Activity.RESULT_OK, null, null, true, UserHandle.USER_SYSTEM,
+ null));
if ((intent.getFlags() & Intent.FLAG_RECEIVER_NO_ABORT) != 0) {
- inOrder.verify(blueThread).scheduleReceiver(
- argThat(filterEqualsIgnoringComponent(intent)), any(), any(),
- eq(Activity.RESULT_OK), any(), any(), eq(true), eq(UserHandle.USER_SYSTEM),
- anyInt());
+ inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver(
+ filterEqualsIgnoringComponent(intent), null, null,
+ Activity.RESULT_OK, null, null, true, UserHandle.USER_SYSTEM,
+ null));
} else {
- inOrder.verify(blueThread, never()).scheduleReceiver(any(), any(), any(), anyInt(),
- any(), any(), anyBoolean(), anyInt(), anyInt());
+ inOrder.verify(blueThread, never()).scheduleReceiverList(manifestReceiver(
+ null, null, null, null,
+ null, null, null, null, null));
}
- inOrder.verify(redThread).scheduleRegisteredReceiver(any(), argThat(filterEquals(intent)),
- eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)),
- eq(false), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+ inOrder.verify(redThread).scheduleReceiverList(registeredReceiver(
+ null, filterEquals(intent),
+ Activity.RESULT_OK, null, bundleEquals(expectedExtras),
+ false, null, UserHandle.USER_SYSTEM, null));
}
/**
@@ -1351,9 +1491,10 @@ public class BroadcastQueueTest {
orderedResultTo, orderedExtras));
waitForIdle();
- verify(callerThread).scheduleRegisteredReceiver(any(), argThat(filterEquals(airplane)),
- eq(Activity.RESULT_OK), any(), argThat(bundleEquals(orderedExtras)), eq(false),
- anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+ verify(callerThread).scheduleReceiverList(registeredReceiver(
+ null, filterEquals(airplane),
+ Activity.RESULT_OK, null, bundleEquals(orderedExtras), false,
+ null, UserHandle.USER_SYSTEM, null));
}
/**
@@ -1371,9 +1512,10 @@ public class BroadcastQueueTest {
makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)), resultTo));
waitForIdle();
- verify(callerThread).scheduleRegisteredReceiver(any(), argThat(filterEquals(airplane)),
- eq(Activity.RESULT_OK), any(), any(), eq(false),
- anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+ verify(callerThread).scheduleReceiverList(registeredReceiver(
+ null, filterEquals(airplane),
+ Activity.RESULT_OK, null, null, false,
+ null, UserHandle.USER_SYSTEM, null));
}
/**
@@ -1536,28 +1678,28 @@ public class BroadcastQueueTest {
final InOrder inOrder = inOrder(callerThread, blueThread);
// First broadcast is canceled
- inOrder.verify(callerThread).scheduleRegisteredReceiver(any(),
- argThat(filterAndExtrasEquals(timezoneFirst)), eq(Activity.RESULT_CANCELED), any(),
- any(), eq(false), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+ inOrder.verify(callerThread).scheduleReceiverList(registeredReceiver(null,
+ filterAndExtrasEquals(timezoneFirst), Activity.RESULT_CANCELED, null,
+ null, false, null, UserHandle.USER_SYSTEM, null));
// We deliver second broadcast to app
timezoneSecond.setClassName(PACKAGE_BLUE, CLASS_GREEN);
- inOrder.verify(blueThread).scheduleReceiver(
- argThat(filterAndExtrasEquals(timezoneSecond)),
- any(), any(), anyInt(), any(), any(), eq(true), anyInt(), anyInt());
+ inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver(
+ filterAndExtrasEquals(timezoneSecond),
+ null, null, null, null, null, true, null, null));
// Second broadcast is finished
timezoneSecond.setComponent(null);
- inOrder.verify(callerThread).scheduleRegisteredReceiver(any(),
- argThat(filterAndExtrasEquals(timezoneSecond)), eq(Activity.RESULT_OK), any(),
- any(), eq(false), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+ inOrder.verify(callerThread).scheduleReceiverList(registeredReceiver(null,
+ filterAndExtrasEquals(timezoneSecond), Activity.RESULT_OK, null,
+ null, false, null, UserHandle.USER_SYSTEM, null));
// Since we "replaced" the first broadcast in its original position,
// only now do we see the airplane broadcast
airplane.setClassName(PACKAGE_BLUE, CLASS_RED);
- inOrder.verify(blueThread).scheduleReceiver(
- argThat(filterEquals(airplane)),
- any(), any(), anyInt(), any(), any(), eq(false), anyInt(), anyInt());
+ inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver(
+ filterEquals(airplane),
+ null, null, null, null, null, false, null, null));
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 5e5cbdc22a23..45247595b678 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -169,6 +169,18 @@ public class LocalDisplayAdapterTest {
.thenReturn(mockArray);
when(mMockedResources.obtainTypedArray(R.array.config_builtInDisplayIsRoundArray))
.thenReturn(mockArray);
+ when(mMockedResources.getIntArray(
+ com.android.internal.R.array.config_brightnessThresholdsOfPeakRefreshRate))
+ .thenReturn(new int[]{});
+ when(mMockedResources.getIntArray(
+ com.android.internal.R.array.config_ambientThresholdsOfPeakRefreshRate))
+ .thenReturn(new int[]{});
+ when(mMockedResources.getIntArray(
+ com.android.internal.R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate))
+ .thenReturn(new int[]{});
+ when(mMockedResources.getIntArray(
+ com.android.internal.R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate))
+ .thenReturn(new int[]{});
}
@After
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
index 6e4d21456cd0..a9dc4af07bab 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
@@ -113,7 +113,8 @@ public final class JobConcurrencyManagerTest {
@Override
JobServiceContext createJobServiceContext(JobSchedulerService service,
- JobConcurrencyManager concurrencyManager, IBatteryStats batteryStats,
+ JobConcurrencyManager concurrencyManager,
+ JobNotificationCoordinator notificationCoordinator, IBatteryStats batteryStats,
JobPackageTracker tracker, Looper looper) {
final JobServiceContext context = mock(JobServiceContext.class);
doAnswer((Answer<Boolean>) invocationOnMock -> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java
new file mode 100644
index 000000000000..b4104dbc89f9
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.job;
+
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.job.JobService;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+public class JobNotificationCoordinatorTest {
+ private static final String TEST_PACKAGE = "com.android.test";
+ private static final String NOTIFICATION_CHANNEL_ID = "validNotificationChannelId";
+
+ private MockitoSession mMockingSession;
+
+ @Mock
+ private NotificationManagerInternal mNotificationManagerInternal;
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(LocalServices.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ doReturn(mNotificationManagerInternal)
+ .when(() -> LocalServices.getService(NotificationManagerInternal.class));
+ doNothing().when(mNotificationManagerInternal)
+ .enqueueNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), any(), anyInt());
+ doNothing().when(mNotificationManagerInternal)
+ .enqueueNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), any(), anyInt());
+ doReturn(mock(NotificationChannel.class)).when(mNotificationManagerInternal)
+ .getNotificationChannel(anyString(), anyInt(), eq(NOTIFICATION_CHANNEL_ID));
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void testParameterValidation() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc = mock(JobServiceContext.class);
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId = 23;
+
+ try {
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId, null,
+ JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ fail("Successfully enqueued a null notification");
+ } catch (NullPointerException e) {
+ // Success
+ }
+
+ Notification notification = createValidNotification();
+ doReturn(null).when(notification).getSmallIcon();
+ try {
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId,
+ notification, JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ fail("Successfully enqueued a notification with no small icon");
+ } catch (IllegalArgumentException e) {
+ // Success
+ }
+
+ notification = createValidNotification();
+ doReturn(null).when(notification).getChannelId();
+ try {
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId,
+ notification, JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ fail("Successfully enqueued a notification with no valid channel");
+ } catch (IllegalArgumentException e) {
+ // Success
+ }
+
+ notification = createValidNotification();
+ try {
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId,
+ notification, Integer.MAX_VALUE);
+ fail("Successfully enqueued a notification with an invalid job end notification "
+ + "policy");
+ } catch (IllegalArgumentException e) {
+ // Success
+ }
+ }
+
+ @Test
+ public void testSingleJob_DetachOnStop() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc = mock(JobServiceContext.class);
+ final Notification notification = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId = 23;
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId, notification,
+ JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification), eq(UserHandle.getUserId(uid)));
+
+ coordinator.removeNotificationAssociation(jsc);
+ verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+ }
+
+ @Test
+ public void testSingleJob_RemoveOnStop() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc = mock(JobServiceContext.class);
+ final Notification notification = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId = 23;
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId, notification,
+ JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification), eq(UserHandle.getUserId(uid)));
+
+ coordinator.removeNotificationAssociation(jsc);
+ verify(mNotificationManagerInternal)
+ .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(UserHandle.getUserId(uid)));
+ }
+
+ @Test
+ public void testSingleJob_EnqueueDifferentNotificationId_DetachOnStop() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc = mock(JobServiceContext.class);
+ final Notification notification1 = createValidNotification();
+ final Notification notification2 = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId1 = 23;
+ final int notificationId2 = 46;
+
+ InOrder inOrder = inOrder(mNotificationManagerInternal);
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId1, notification1,
+ JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId1), eq(notification1), eq(UserHandle.getUserId(uid)));
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId2, notification2,
+ JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId2), eq(notification2), eq(UserHandle.getUserId(uid)));
+ }
+
+ @Test
+ public void testSingleJob_EnqueueDifferentNotificationId_RemoveOnStop() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc = mock(JobServiceContext.class);
+ final Notification notification1 = createValidNotification();
+ final Notification notification2 = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId1 = 23;
+ final int notificationId2 = 46;
+
+ InOrder inOrder = inOrder(mNotificationManagerInternal);
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId1, notification1,
+ JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId1), eq(notification1), eq(UserHandle.getUserId(uid)));
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId2, notification2,
+ JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId1), eq(UserHandle.getUserId(uid)));
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId2), eq(notification2), eq(UserHandle.getUserId(uid)));
+ }
+
+ @Test
+ public void testSingleJob_EnqueueSameNotificationId() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc = mock(JobServiceContext.class);
+ final Notification notification1 = createValidNotification();
+ final Notification notification2 = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId = 23;
+
+ InOrder inOrder = inOrder(mNotificationManagerInternal);
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId, notification1,
+ JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification1), eq(UserHandle.getUserId(uid)));
+
+ coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId, notification2,
+ JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid)));
+ }
+
+ @Test
+ public void testMultipleJobs_sameApp_EnqueueDifferentNotificationId() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc1 = mock(JobServiceContext.class);
+ final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final Notification notification1 = createValidNotification();
+ final Notification notification2 = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId1 = 23;
+ final int notificationId2 = 46;
+
+ InOrder inOrder = inOrder(mNotificationManagerInternal);
+
+ coordinator.enqueueNotification(jsc1, TEST_PACKAGE, pid, uid, notificationId1,
+ notification1, JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId1), eq(notification1), eq(UserHandle.getUserId(uid)));
+
+ coordinator.enqueueNotification(jsc2, TEST_PACKAGE, pid, uid, notificationId2,
+ notification2, JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId2), eq(notification2), eq(UserHandle.getUserId(uid)));
+
+ // Remove the first job. Only the first notification should be removed.
+ coordinator.removeNotificationAssociation(jsc1);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId1), eq(UserHandle.getUserId(uid)));
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ eq(notificationId2), anyInt());
+
+ coordinator.removeNotificationAssociation(jsc2);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId2), eq(UserHandle.getUserId(uid)));
+ }
+
+ @Test
+ public void testMultipleJobs_sameApp_EnqueueSameNotificationId() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc1 = mock(JobServiceContext.class);
+ final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final Notification notification1 = createValidNotification();
+ final Notification notification2 = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId = 23;
+
+ InOrder inOrder = inOrder(mNotificationManagerInternal);
+
+ coordinator.enqueueNotification(jsc1, TEST_PACKAGE, pid, uid, notificationId, notification1,
+ JobService.JOB_END_NOTIFICATION_POLICY_DETACH);
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification1), eq(UserHandle.getUserId(uid)));
+
+ coordinator.enqueueNotification(jsc2, TEST_PACKAGE, pid, uid, notificationId, notification2,
+ JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid)));
+
+ // Remove the first job. The notification shouldn't be touched because of the 2nd job.
+ coordinator.removeNotificationAssociation(jsc1);
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+
+ coordinator.removeNotificationAssociation(jsc2);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(UserHandle.getUserId(uid)));
+ }
+
+ @Test
+ public void testMultipleJobs_sameApp_DifferentUsers() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final JobServiceContext jsc1 = mock(JobServiceContext.class);
+ final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final Notification notification1 = createValidNotification();
+ final Notification notification2 = createValidNotification();
+ final int uid1 = 10123;
+ final int uid2 = 1010123;
+ final int pid = 42;
+ final int notificationId = 23;
+
+ InOrder inOrder = inOrder(mNotificationManagerInternal);
+
+ coordinator.enqueueNotification(jsc1, TEST_PACKAGE, pid, uid1, notificationId,
+ notification1, JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid1), eq(pid), any(),
+ eq(notificationId), eq(notification1), eq(UserHandle.getUserId(uid1)));
+
+ coordinator.enqueueNotification(jsc2, TEST_PACKAGE, pid, uid2, notificationId,
+ notification2, JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid2), eq(pid), any(),
+ eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid2)));
+
+ // Remove the first job. Only the first notification should be removed.
+ coordinator.removeNotificationAssociation(jsc1);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid1), eq(pid), any(),
+ eq(notificationId), eq(UserHandle.getUserId(uid1)));
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), eq(uid2), anyInt(), any(),
+ anyInt(), anyInt());
+
+ coordinator.removeNotificationAssociation(jsc2);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid2), eq(pid), any(),
+ eq(notificationId), eq(UserHandle.getUserId(uid2)));
+ }
+
+ @Test
+ public void testMultipleJobs_differentApps() {
+ final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
+ final String pkg1 = "pkg1";
+ final String pkg2 = "pkg2";
+ final JobServiceContext jsc1 = mock(JobServiceContext.class);
+ final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final Notification notification1 = createValidNotification();
+ final Notification notification2 = createValidNotification();
+ final int uid = 10123;
+ final int pid = 42;
+ final int notificationId = 23;
+
+ InOrder inOrder = inOrder(mNotificationManagerInternal);
+
+ coordinator.enqueueNotification(jsc1, pkg1, pid, uid, notificationId, notification1,
+ JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(pkg1), eq(pkg1), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification1), eq(UserHandle.getUserId(uid)));
+
+ coordinator.enqueueNotification(jsc2, pkg2, pid, uid, notificationId, notification2,
+ JobService.JOB_END_NOTIFICATION_POLICY_REMOVE);
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(),
+ anyInt(), anyInt());
+ inOrder.verify(mNotificationManagerInternal)
+ .enqueueNotification(eq(pkg2), eq(pkg2), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid)));
+
+ // Remove the first job. Only the first notification should be removed.
+ coordinator.removeNotificationAssociation(jsc1);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(pkg1), eq(pkg1), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(UserHandle.getUserId(uid)));
+ inOrder.verify(mNotificationManagerInternal, never())
+ .cancelNotification(anyString(), anyString(), eq(uid), anyInt(), any(),
+ anyInt(), anyInt());
+
+ coordinator.removeNotificationAssociation(jsc2);
+ inOrder.verify(mNotificationManagerInternal)
+ .cancelNotification(eq(pkg2), eq(pkg2), eq(uid), eq(pid), any(),
+ eq(notificationId), eq(UserHandle.getUserId(uid)));
+ }
+
+ private Notification createValidNotification() {
+ final Notification notification = mock(Notification.class);
+ doReturn(mock(Icon.class)).when(notification).getSmallIcon();
+ doReturn(NOTIFICATION_CHANNEL_ID).when(notification).getChannelId();
+ return notification;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 8e4849043984..0eeebca61094 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -68,6 +68,8 @@ import com.android.server.PowerAllowlistInternal;
import com.android.server.SystemServiceManager;
import com.android.server.job.controllers.ConnectivityController;
import com.android.server.job.controllers.JobStatus;
+import com.android.server.job.controllers.QuotaController;
+import com.android.server.job.controllers.TareController;
import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal;
@@ -336,14 +338,29 @@ public class JobSchedulerServiceTest {
when(jobUI.shouldTreatAsUserInitiated()).thenReturn(true);
when(jobUIDT.shouldTreatAsUserInitiated()).thenReturn(true);
- grantRunLongJobsPermission(true);
+ QuotaController quotaController = mService.getQuotaController();
+ spyOn(quotaController);
+ TareController tareController = mService.getTareController();
+ spyOn(tareController);
+ doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
+ .when(quotaController).getMaxJobExecutionTimeMsLocked(any());
+ doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
+ .when(quotaController).getMaxJobExecutionTimeMsLocked(any());
+ grantRunLongJobsPermission(true);
assertEquals(mService.mConstants.RUNTIME_DATA_TRANSFER_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobDT));
assertEquals(mService.mConstants.RUNTIME_USER_INITIATED_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUI));
assertEquals(mService.mConstants.RUNTIME_USER_INITIATED_DATA_TRANSFER_LIMIT_MS,
mService.getMaxJobExecutionTimeMs(jobUIDT));
+ grantRunLongJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_DATA_TRANSFER_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobDT));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUI));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUIDT));
}
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 17822c6d5004..d72ccf813445 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -2163,6 +2163,31 @@ public class QuotaControllerTest {
}
@Test
+ public void testIsWithinQuotaLocked_UserInitiated() {
+ // Put app in a state where regular jobs are out of quota.
+ setDischarging();
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW;
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25), false);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount),
+ false);
+ JobStatus job = createJobStatus("testIsWithinQuotaLocked_UserInitiated", 1);
+ spyOn(job);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.incrementJobCountLocked(SOURCE_USER_ID, SOURCE_PACKAGE, jobCount);
+ assertFalse(mQuotaController
+ .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
+ doReturn(false).when(job).shouldTreatAsUserInitiated();
+ assertFalse(mQuotaController.isWithinQuotaLocked(job));
+ // User-initiated job should still be allowed.
+ doReturn(true).when(job).shouldTreatAsUserInitiated();
+ assertTrue(mQuotaController.isWithinQuotaLocked(job));
+ }
+ }
+
+ @Test
public void testIsWithinQuotaLocked_WithQuotaBump_Duration() {
setDischarging();
int standbyBucket = WORKING_INDEX;
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java
index f88e18b4ced1..49426901b142 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java
@@ -180,14 +180,47 @@ public class ThermalStatusRestrictionTest {
createJobBuilder(7).setExpedited(true).build());
final JobStatus ej = spy(createJobStatus("testIsJobRestricted",
createJobBuilder(8).setExpedited(true).build()));
+ final JobStatus ejRetried = spy(createJobStatus("testIsJobRestricted",
+ createJobBuilder(11).setExpedited(true).build()));
+ final JobStatus ejRunning = spy(createJobStatus("testIsJobRestricted",
+ createJobBuilder(12).setExpedited(true).build()));
+ final JobStatus ejRunningLong = spy(createJobStatus("testIsJobRestricted",
+ createJobBuilder(13).setExpedited(true).build()));
+ final JobStatus ui = spy(createJobStatus("testIsJobRestricted",
+ createJobBuilder(14).build()));
+ final JobStatus uiRetried = spy(createJobStatus("testIsJobRestricted",
+ createJobBuilder(15).build()));
+ final JobStatus uiRunning = spy(createJobStatus("testIsJobRestricted",
+ createJobBuilder(16).build()));
+ final JobStatus uiRunningLong = spy(createJobStatus("testIsJobRestricted",
+ createJobBuilder(17).build()));
when(ej.shouldTreatAsExpeditedJob()).thenReturn(true);
+ when(ejRetried.shouldTreatAsExpeditedJob()).thenReturn(true);
+ when(ejRunning.shouldTreatAsExpeditedJob()).thenReturn(true);
+ when(ejRunningLong.shouldTreatAsExpeditedJob()).thenReturn(true);
+ when(ui.shouldTreatAsUserInitiated()).thenReturn(true);
+ when(uiRetried.shouldTreatAsUserInitiated()).thenReturn(true);
+ when(uiRunning.shouldTreatAsUserInitiated()).thenReturn(true);
+ when(uiRunningLong.shouldTreatAsUserInitiated()).thenReturn(true);
+ when(ejRetried.getNumPreviousAttempts()).thenReturn(1);
+ when(uiRetried.getNumPreviousAttempts()).thenReturn(2);
when(mJobSchedulerService.isCurrentlyRunningLocked(jobLowPriorityRunning)).thenReturn(true);
when(mJobSchedulerService.isCurrentlyRunningLocked(jobHighPriorityRunning))
.thenReturn(true);
+ when(mJobSchedulerService.isCurrentlyRunningLocked(jobLowPriorityRunningLong))
+ .thenReturn(true);
+ when(mJobSchedulerService.isCurrentlyRunningLocked(jobHighPriorityRunningLong))
+ .thenReturn(true);
+ when(mJobSchedulerService.isCurrentlyRunningLocked(ejRunning)).thenReturn(true);
+ when(mJobSchedulerService.isCurrentlyRunningLocked(ejRunningLong)).thenReturn(true);
+ when(mJobSchedulerService.isCurrentlyRunningLocked(uiRunning)).thenReturn(true);
+ when(mJobSchedulerService.isCurrentlyRunningLocked(uiRunningLong)).thenReturn(true);
when(mJobSchedulerService.isJobInOvertimeLocked(jobLowPriorityRunningLong))
.thenReturn(true);
when(mJobSchedulerService.isJobInOvertimeLocked(jobHighPriorityRunningLong))
.thenReturn(true);
+ when(mJobSchedulerService.isJobInOvertimeLocked(ejRunningLong)).thenReturn(true);
+ when(mJobSchedulerService.isJobInOvertimeLocked(uiRunningLong)).thenReturn(true);
assertFalse(mThermalStatusRestriction.isJobRestricted(jobMinPriority));
assertFalse(mThermalStatusRestriction.isJobRestricted(jobLowPriority));
@@ -199,6 +232,13 @@ public class ThermalStatusRestrictionTest {
assertFalse(mThermalStatusRestriction.isJobRestricted(jobHighPriorityRunningLong));
assertFalse(mThermalStatusRestriction.isJobRestricted(ej));
assertFalse(mThermalStatusRestriction.isJobRestricted(ejDowngraded));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ejRetried));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ejRunning));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ejRunningLong));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ui));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(uiRetried));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(uiRunning));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(uiRunningLong));
mStatusChangedListener.onThermalStatusChanged(THERMAL_STATUS_LIGHT);
@@ -212,6 +252,13 @@ public class ThermalStatusRestrictionTest {
assertFalse(mThermalStatusRestriction.isJobRestricted(jobHighPriorityRunningLong));
assertFalse(mThermalStatusRestriction.isJobRestricted(ejDowngraded));
assertFalse(mThermalStatusRestriction.isJobRestricted(ej));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ejRetried));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ejRunning));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ejRunningLong));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ui));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(uiRetried));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(uiRunning));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(uiRunningLong));
mStatusChangedListener.onThermalStatusChanged(THERMAL_STATUS_MODERATE);
@@ -225,6 +272,13 @@ public class ThermalStatusRestrictionTest {
assertTrue(mThermalStatusRestriction.isJobRestricted(jobHighPriorityRunningLong));
assertTrue(mThermalStatusRestriction.isJobRestricted(ejDowngraded));
assertFalse(mThermalStatusRestriction.isJobRestricted(ej));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRetried));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ejRunning));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRunningLong));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(ui));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRetried));
+ assertFalse(mThermalStatusRestriction.isJobRestricted(uiRunning));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRunningLong));
mStatusChangedListener.onThermalStatusChanged(THERMAL_STATUS_SEVERE);
@@ -238,6 +292,13 @@ public class ThermalStatusRestrictionTest {
assertTrue(mThermalStatusRestriction.isJobRestricted(jobHighPriorityRunningLong));
assertTrue(mThermalStatusRestriction.isJobRestricted(ejDowngraded));
assertTrue(mThermalStatusRestriction.isJobRestricted(ej));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRetried));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRunning));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRunningLong));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ui));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRetried));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRunning));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRunningLong));
mStatusChangedListener.onThermalStatusChanged(THERMAL_STATUS_CRITICAL);
@@ -251,6 +312,13 @@ public class ThermalStatusRestrictionTest {
assertTrue(mThermalStatusRestriction.isJobRestricted(jobHighPriorityRunningLong));
assertTrue(mThermalStatusRestriction.isJobRestricted(ejDowngraded));
assertTrue(mThermalStatusRestriction.isJobRestricted(ej));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRetried));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRunning));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ejRunningLong));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(ui));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRetried));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRunning));
+ assertTrue(mThermalStatusRestriction.isJobRestricted(uiRunningLong));
}
private JobInfo.Builder createJobBuilder(int jobId) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java
new file mode 100644
index 000000000000..4d112965b932
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.location.ILocationListener;
+import android.location.LocationManagerInternal;
+import android.location.LocationRequest;
+import android.location.provider.ProviderRequest;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.LocalServices;
+import com.android.server.location.injector.FakeUserInfoHelper;
+import com.android.server.location.injector.TestInjector;
+import com.android.server.location.provider.AbstractLocationProvider;
+import com.android.server.location.provider.LocationProviderManager;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+
+import com.google.common.util.concurrent.MoreExecutors;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import java.util.Collections;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocationManagerServiceTest {
+ private static final String PROVIDER_WITH_PERMISSION = "provider_with_permission";
+ private static final String PROVIDER_WITHOUT_PERMISSION = "provider_without_permission";
+ private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+ private static final String CALLER_PACKAGE = "caller_package";
+ private static final String MISSING_PERMISSION = "missing_permission";
+
+ private TestInjector mInjector;
+ private LocationManagerService mLocationManagerService;
+
+ @Spy private FakeAbstractLocationProvider mProviderWithPermission;
+ @Spy private FakeAbstractLocationProvider mProviderWithoutPermission;
+ @Mock private ILocationListener mLocationListener;
+ @Mock private IBinder mBinder;
+ @Mock private Context mContext;
+ @Mock private Resources mResources;
+ @Mock private PackageManager mPackageManager;
+ @Mock private AppOpsManager mAppOpsManager;
+ @Mock private PowerManager mPowerManager;
+ @Mock private PowerManager.WakeLock mWakeLock;
+ @Mock private LegacyPermissionManagerInternal mPermissionManagerInternal;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+
+ doReturn(mContext).when(mContext).createAttributionContext(any());
+ 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());
+ doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
+ String[] packages = {CALLER_PACKAGE};
+ doReturn(InstrumentationRegistry.getInstrumentation().getContext().getContentResolver())
+ .when(mContext)
+ .getContentResolver();
+ doReturn(packages).when(mPackageManager).getPackagesForUid(anyInt());
+ doReturn(mBinder).when(mLocationListener).asBinder();
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mContext)
+ .checkCallingOrSelfPermission(MISSING_PERMISSION);
+
+ mInjector = new TestInjector(mContext);
+ mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
+
+ LocalServices.addService(LegacyPermissionManagerInternal.class, mPermissionManagerInternal);
+
+ mLocationManagerService = new LocationManagerService(mContext, mInjector);
+
+ LocationProviderManager managerWithPermission =
+ new LocationProviderManager(
+ mContext, mInjector, PROVIDER_WITH_PERMISSION, /* passiveManager= */ null);
+ mLocationManagerService.addLocationProviderManager(
+ managerWithPermission, mProviderWithPermission);
+ LocationProviderManager managerWithoutPermission =
+ new LocationProviderManager(
+ mContext,
+ mInjector,
+ PROVIDER_WITHOUT_PERMISSION,
+ /* passiveManager= */ null,
+ Collections.singletonList(MISSING_PERMISSION));
+ mLocationManagerService.addLocationProviderManager(
+ managerWithoutPermission, mProviderWithoutPermission);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(LegacyPermissionManagerInternal.class);
+ LocalServices.removeServiceForTest(LocationManagerInternal.class);
+ }
+
+ @Test
+ public void testRequestLocationUpdates() {
+ LocationRequest request = new LocationRequest.Builder(0).build();
+ mLocationManagerService.registerLocationListener(
+ PROVIDER_WITH_PERMISSION,
+ request,
+ mLocationListener,
+ CALLER_PACKAGE,
+ /* attributionTag= */ null,
+ "any_listener_id");
+ verify(mProviderWithPermission).onSetRequestPublic(any());
+ }
+
+ @Test
+ public void testRequestLocationUpdates_noPermission() {
+ LocationRequest request = new LocationRequest.Builder(0).build();
+ assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ mLocationManagerService.registerLocationListener(
+ PROVIDER_WITHOUT_PERMISSION,
+ request,
+ mLocationListener,
+ CALLER_PACKAGE,
+ /* attributionTag= */ null,
+ "any_listener_id"));
+ }
+
+ @Test
+ public void testHasProvider() {
+ assertThat(mLocationManagerService.hasProvider(PROVIDER_WITH_PERMISSION)).isTrue();
+ }
+
+ @Test
+ public void testHasProvider_noPermission() {
+ assertThat(mLocationManagerService.hasProvider(PROVIDER_WITHOUT_PERMISSION)).isFalse();
+ }
+
+ @Test
+ public void testGetAllProviders() {
+ assertThat(mLocationManagerService.getAllProviders()).contains(PROVIDER_WITH_PERMISSION);
+ assertThat(mLocationManagerService.getAllProviders())
+ .doesNotContain(PROVIDER_WITHOUT_PERMISSION);
+ }
+
+ abstract static class FakeAbstractLocationProvider extends AbstractLocationProvider {
+ FakeAbstractLocationProvider() {
+ super(
+ MoreExecutors.directExecutor(),
+ /* identity= */ null,
+ /* properties= */ null,
+ /* extraAttributionTags= */ Collections.emptySet());
+ setAllowed(true);
+ }
+
+ @Override
+ protected void onSetRequest(ProviderRequest request) {
+ // Call a public version of this method so mockito can verify.
+ onSetRequestPublic(request);
+ }
+
+ public abstract void onSetRequestPublic(ProviderRequest request);
+ }
+}
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 aa28ad489027..7dc1935f89ba 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
@@ -102,6 +102,7 @@ import org.mockito.Mock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -133,6 +134,7 @@ public class LocationProviderManagerTest {
private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
"mypackage", "attribution", "listener");
private static final WorkSource WORK_SOURCE = new WorkSource(IDENTITY.getUid());
+ private static final String MISSING_PERMISSION = "missing_permission";
private Random mRandom;
@@ -173,6 +175,9 @@ public class LocationProviderManagerTest {
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mContext)
+ .checkCallingOrSelfPermission(MISSING_PERMISSION);
mInjector = new TestInjector(mContext);
mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
@@ -187,12 +192,18 @@ public class LocationProviderManagerTest {
}
private void createManager(String name) {
+ createManager(name, Collections.emptyList());
+ }
+
+ private void createManager(String name, Collection<String> requiredPermissions) {
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, requiredPermissions);
mManager.startManager(mStateChangedListener);
mManager.setRealProvider(mProvider);
}
@@ -1317,6 +1328,17 @@ public class LocationProviderManagerTest {
assertThat(mInjector.getPackageResetHelper().isResetableForPackage("mypackage")).isFalse();
}
+ @Test
+ public void testIsVisibleToCaller() {
+ assertThat(mManager.isVisibleToCaller()).isTrue();
+ }
+
+ @Test
+ public void testIsVisibleToCaller_noPermissions() {
+ createManager("any_name", Collections.singletonList(MISSING_PERMISSION));
+ assertThat(mManager.isVisibleToCaller()).isFalse();
+ }
+
private ILocationListener createMockLocationListener() {
return spy(new ILocationListener.Stub() {
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 27d0662d118e..4f562710c789 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -193,6 +193,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
val incrementalManager: IncrementalManager = mock()
val platformCompat: PlatformCompat = mock()
val settings: Settings = mock()
+ val crossProfileIntentFilterHelper: CrossProfileIntentFilterHelper = mock()
val resources: Resources = mock()
val systemConfig: SystemConfig = mock()
val apexManager: ApexManager = mock()
@@ -279,6 +280,8 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
whenever(mocks.injector.incrementalManager).thenReturn(mocks.incrementalManager)
whenever(mocks.injector.compatibility).thenReturn(mocks.platformCompat)
whenever(mocks.injector.settings).thenReturn(mocks.settings)
+ whenever(mocks.injector.crossProfileIntentFilterHelper)
+ .thenReturn(mocks.crossProfileIntentFilterHelper)
whenever(mocks.injector.dexManager).thenReturn(mocks.dexManager)
whenever(mocks.injector.systemConfig).thenReturn(mocks.systemConfig)
whenever(mocks.injector.apexManager).thenReturn(mocks.apexManager)
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ThermalManagerServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ThermalManagerServiceMockingTest.java
new file mode 100644
index 000000000000..34b17c7901b3
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/power/ThermalManagerServiceMockingTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.power;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.hardware.thermal.CoolingType;
+import android.hardware.thermal.IThermal;
+import android.hardware.thermal.IThermalChangedCallback;
+import android.hardware.thermal.TemperatureThreshold;
+import android.hardware.thermal.TemperatureType;
+import android.hardware.thermal.ThrottlingSeverity;
+import android.os.Binder;
+import android.os.CoolingDevice;
+import android.os.RemoteException;
+import android.os.Temperature;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+
+public class ThermalManagerServiceMockingTest {
+ @Mock private IThermal mAidlHalMock;
+ private Binder mAidlBinder = new Binder();
+ private CompletableFuture<Temperature> mTemperatureFuture;
+ private ThermalManagerService.ThermalHalWrapper.TemperatureChangedCallback mTemperatureCallback;
+ private ThermalManagerService.ThermalHalAidlWrapper mAidlWrapper;
+ @Captor
+ ArgumentCaptor<IThermalChangedCallback> mAidlCallbackCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Mockito.when(mAidlHalMock.asBinder()).thenReturn(mAidlBinder);
+ mAidlBinder.attachInterface(mAidlHalMock, IThermal.class.getName());
+ mTemperatureFuture = new CompletableFuture<>();
+ mTemperatureCallback = temperature -> mTemperatureFuture.complete(temperature);
+ mAidlWrapper = new ThermalManagerService.ThermalHalAidlWrapper();
+ mAidlWrapper.setCallback(mTemperatureCallback);
+ mAidlWrapper.initProxyAndRegisterCallback(mAidlBinder);
+ }
+
+ @Test
+ public void setCallback_aidl() throws Exception {
+ Mockito.verify(mAidlHalMock, Mockito.times(1)).registerThermalChangedCallback(
+ mAidlCallbackCaptor.capture());
+ android.hardware.thermal.Temperature halT =
+ new android.hardware.thermal.Temperature();
+ halT.type = TemperatureType.SOC;
+ halT.name = "test";
+ halT.throttlingStatus = ThrottlingSeverity.SHUTDOWN;
+ halT.value = 99.0f;
+ mAidlCallbackCaptor.getValue().notifyThrottling(halT);
+ Temperature temperature = mTemperatureFuture.get(100, TimeUnit.MILLISECONDS);
+ assertEquals(halT.name, temperature.getName());
+ assertEquals(halT.type, temperature.getType());
+ assertEquals(halT.value, temperature.getValue(), 0.1f);
+ assertEquals(halT.throttlingStatus, temperature.getStatus());
+ }
+
+ @Test
+ public void getCurrentTemperatures_withFilter_aidl() throws RemoteException {
+ android.hardware.thermal.Temperature halT1 = new android.hardware.thermal.Temperature();
+ halT1.type = TemperatureType.MODEM;
+ halT1.name = "test1";
+ halT1.throttlingStatus = ThrottlingSeverity.EMERGENCY;
+ halT1.value = 99.0f;
+ android.hardware.thermal.Temperature halT2 = new android.hardware.thermal.Temperature();
+ halT2.name = "test2";
+ halT2.type = TemperatureType.MODEM;
+ halT2.throttlingStatus = ThrottlingSeverity.NONE;
+
+ android.hardware.thermal.Temperature halT3WithDiffType =
+ new android.hardware.thermal.Temperature();
+ halT3WithDiffType.type = TemperatureType.BCL_CURRENT;
+ halT3WithDiffType.throttlingStatus = ThrottlingSeverity.CRITICAL;
+
+ Mockito.when(mAidlHalMock.getTemperaturesWithType(Mockito.anyInt())).thenReturn(
+ new android.hardware.thermal.Temperature[]{
+ halT2, halT1, halT3WithDiffType,
+ });
+ List<Temperature> ret = mAidlWrapper.getCurrentTemperatures(true, TemperatureType.MODEM);
+ Mockito.verify(mAidlHalMock, Mockito.times(1)).getTemperaturesWithType(
+ TemperatureType.MODEM);
+
+ Temperature expectedT1 = new Temperature(halT1.value, halT1.type, halT1.name,
+ halT1.throttlingStatus);
+ Temperature expectedT2 = new Temperature(halT2.value, halT2.type, halT2.name,
+ halT2.throttlingStatus);
+ List<Temperature> expectedRet = List.of(expectedT1, expectedT2);
+ assertTrue("Got temperature list as " + ret + " with different values compared to "
+ + expectedRet, expectedRet.containsAll(ret));
+ }
+
+ @Test
+ public void getCurrentTemperatures_invalidStatus_aidl() throws RemoteException {
+ android.hardware.thermal.Temperature halTInvalid =
+ new android.hardware.thermal.Temperature();
+ halTInvalid.name = "test";
+ halTInvalid.type = TemperatureType.MODEM;
+ halTInvalid.throttlingStatus = 99;
+
+ Mockito.when(mAidlHalMock.getTemperatures()).thenReturn(
+ new android.hardware.thermal.Temperature[]{
+ halTInvalid
+ });
+ List<Temperature> ret = mAidlWrapper.getCurrentTemperatures(false, 0);
+ Mockito.verify(mAidlHalMock, Mockito.times(1)).getTemperatures();
+
+ List<Temperature> expectedRet = List.of(
+ new Temperature(halTInvalid.value, halTInvalid.type, halTInvalid.name,
+ ThrottlingSeverity.NONE));
+ assertEquals(expectedRet, ret);
+ }
+
+ @Test
+ public void getCurrentCoolingDevices_withFilter_aidl() throws RemoteException {
+ android.hardware.thermal.CoolingDevice halC1 = new android.hardware.thermal.CoolingDevice();
+ halC1.type = CoolingType.SPEAKER;
+ halC1.name = "test1";
+ halC1.value = 10;
+ android.hardware.thermal.CoolingDevice halC2 = new android.hardware.thermal.CoolingDevice();
+ halC2.type = CoolingType.MODEM;
+ halC2.name = "test2";
+ halC2.value = 110;
+
+ Mockito.when(mAidlHalMock.getCoolingDevicesWithType(Mockito.anyInt())).thenReturn(
+ new android.hardware.thermal.CoolingDevice[]{
+ halC1, halC2
+ }
+ );
+ List<CoolingDevice> ret = mAidlWrapper.getCurrentCoolingDevices(true, CoolingType.SPEAKER);
+ Mockito.verify(mAidlHalMock, Mockito.times(1)).getCoolingDevicesWithType(
+ CoolingType.SPEAKER);
+
+ CoolingDevice expectedC1 = new CoolingDevice(halC1.value, halC1.type, halC1.name);
+ List<CoolingDevice> expectedRet = List.of(expectedC1);
+ assertTrue("Got cooling device list as " + ret + " with different values compared to "
+ + expectedRet, expectedRet.containsAll(ret));
+ }
+
+ @Test
+ public void getCurrentCoolingDevices_invalidType_aidl() throws RemoteException {
+ android.hardware.thermal.CoolingDevice halC1 = new android.hardware.thermal.CoolingDevice();
+ halC1.type = 99;
+ halC1.name = "test1";
+ halC1.value = 10;
+ android.hardware.thermal.CoolingDevice halC2 = new android.hardware.thermal.CoolingDevice();
+ halC2.type = -1;
+ halC2.name = "test2";
+ halC2.value = 110;
+
+ Mockito.when(mAidlHalMock.getCoolingDevices()).thenReturn(
+ new android.hardware.thermal.CoolingDevice[]{
+ halC1, halC2
+ }
+ );
+ List<CoolingDevice> ret = mAidlWrapper.getCurrentCoolingDevices(false, 0);
+ Mockito.verify(mAidlHalMock, Mockito.times(1)).getCoolingDevices();
+
+ assertTrue("Got cooling device list as " + ret + ", expecting empty list", ret.isEmpty());
+ }
+
+ @Test
+ public void getTemperatureThresholds_withFilter_aidl() throws RemoteException {
+ TemperatureThreshold halT1 = new TemperatureThreshold();
+ halT1.name = "test1";
+ halT1.type = Temperature.TYPE_SKIN;
+ halT1.hotThrottlingThresholds = new float[]{1, 2, 3};
+ halT1.coldThrottlingThresholds = new float[]{};
+
+ TemperatureThreshold halT2 = new TemperatureThreshold();
+ halT1.name = "test2";
+ halT1.type = Temperature.TYPE_SOC;
+ halT1.hotThrottlingThresholds = new float[]{};
+ halT1.coldThrottlingThresholds = new float[]{3, 2, 1};
+
+ Mockito.when(mAidlHalMock.getTemperatureThresholdsWithType(Mockito.anyInt())).thenReturn(
+ new TemperatureThreshold[]{halT1, halT2}
+ );
+ List<TemperatureThreshold> ret = mAidlWrapper.getTemperatureThresholds(true,
+ Temperature.TYPE_SOC);
+ Mockito.verify(mAidlHalMock, Mockito.times(1)).getTemperatureThresholdsWithType(
+ Temperature.TYPE_SOC);
+
+ assertEquals("Got unexpected temperature thresholds size", 1, ret.size());
+ TemperatureThreshold threshold = ret.get(0);
+ assertEquals(halT1.name, threshold.name);
+ assertEquals(halT1.type, threshold.type);
+ assertArrayEquals(halT1.hotThrottlingThresholds, threshold.hotThrottlingThresholds, 0.1f);
+ assertArrayEquals(halT1.coldThrottlingThresholds, threshold.coldThrottlingThresholds, 0.1f);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
index 83a597dfad5c..b0ad31d6a430 100644
--- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
@@ -179,8 +179,9 @@ public class CountryDetectorServiceTest {
mCountryDetectorService.systemRunning();
mCountryDetectorService.addCountryListener(countryListenerA);
mCountryDetectorService.addCountryListener(countryListenerB);
- expect.that(countryListenerA.isNotified()).isFalse();
- expect.that(countryListenerB.isNotified()).isFalse();
+ //Immediate Callback Info support at ag/20470367
+ expect.that(countryListenerA.isNotified()).isTrue();
+ expect.that(countryListenerB.isNotified()).isTrue();
mCountryDetectorService.notifyReceivers(country);
expect.that(countryListenerA.isNotified()).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index d47f063caec5..98037d792bf4 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -38,6 +38,8 @@ import static com.android.server.am.UserController.USER_COMPLETED_EVENT_MSG;
import static com.android.server.am.UserController.USER_CURRENT_MSG;
import static com.android.server.am.UserController.USER_START_MSG;
import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
+import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND;
+import static com.android.server.pm.UserManagerInternal.USER_START_MODE_FOREGROUND;
import static com.google.android.collect.Lists.newArrayList;
import static com.google.android.collect.Sets.newHashSet;
@@ -190,7 +192,7 @@ public class UserControllerTest {
// that's not the case, the test should call mockAssignUserToMainDisplay()
doReturn(UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE)
.when(mInjector.mUserManagerInternalMock)
- .assignUserToDisplayOnStart(anyInt(), anyInt(), anyBoolean(), anyInt());
+ .assignUserToDisplayOnStart(anyInt(), anyInt(), anyInt(), anyInt());
mUserController = new UserController(mInjector);
mUserController.setAllowUserUnlocking(true);
@@ -207,7 +209,7 @@ public class UserControllerTest {
@Test
public void testStartUser_foreground() {
- mUserController.startUser(TEST_USER_ID, true /* foreground */);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
@@ -219,7 +221,7 @@ public class UserControllerTest {
@Test
public void testStartUser_background() {
- boolean started = mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
+ boolean started = mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND);
assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue();
verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
@@ -232,9 +234,10 @@ public class UserControllerTest {
public void testStartUser_displayAssignmentFailed() {
doReturn(UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE)
.when(mInjector.mUserManagerInternalMock)
- .assignUserToDisplayOnStart(eq(TEST_USER_ID), anyInt(), eq(true), anyInt());
+ .assignUserToDisplayOnStart(eq(TEST_USER_ID), anyInt(),
+ eq(USER_START_MODE_FOREGROUND), anyInt());
- boolean started = mUserController.startUser(TEST_USER_ID, /* foreground= */ true);
+ boolean started = mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
assertWithMessage("startUser(%s, foreground=true)", TEST_USER_ID).that(started).isFalse();
}
@@ -266,7 +269,7 @@ public class UserControllerTest {
mUserController.setInitialConfig(/* userSwitchUiEnabled= */ false,
/* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
- mUserController.startUser(TEST_USER_ID, /* foreground= */ true);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
@@ -275,7 +278,8 @@ public class UserControllerTest {
@Test
public void testStartPreCreatedUser_foreground() {
- assertFalse(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ true));
+ assertFalse(
+ mUserController.startUser(TEST_PRE_CREATED_USER_ID, USER_START_MODE_FOREGROUND));
// Make sure no intents have been fired for pre-created users.
assertTrue(mInjector.mSentIntents.isEmpty());
@@ -284,7 +288,7 @@ public class UserControllerTest {
@Test
public void testStartPreCreatedUser_background() throws Exception {
- assertTrue(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ false));
+ assertTrue(mUserController.startUser(TEST_PRE_CREATED_USER_ID, USER_START_MODE_BACKGROUND));
// Make sure no intents have been fired for pre-created users.
assertTrue(mInjector.mSentIntents.isEmpty());
@@ -352,7 +356,7 @@ public class UserControllerTest {
}).when(observer).onUserSwitching(anyInt(), any());
mUserController.registerUserSwitchObserver(observer, "mock");
// Start user -- this will update state of mUserController
- mUserController.startUser(TEST_USER_ID, true);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -382,7 +386,7 @@ public class UserControllerTest {
when(observer.asBinder()).thenReturn(new Binder());
mUserController.registerUserSwitchObserver(observer, "mock");
// Start user -- this will update state of mUserController
- mUserController.startUser(TEST_USER_ID, true);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -408,7 +412,7 @@ public class UserControllerTest {
mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
/* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
// Start user -- this will update state of mUserController
- mUserController.startUser(TEST_USER_ID, true);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -429,7 +433,7 @@ public class UserControllerTest {
mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
/* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
// Start user -- this will update state of mUserController
- mUserController.startUser(TEST_USER_ID, /* foreground=*/ true);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -450,7 +454,7 @@ public class UserControllerTest {
/* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
// Start user -- this will update state of mUserController
- mUserController.startUser(TEST_USER_ID, /* foreground=*/ true);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -487,7 +491,7 @@ public class UserControllerTest {
when(observer.asBinder()).thenReturn(new Binder());
mUserController.registerUserSwitchObserver(observer, "mock");
// Start user -- this will update state of mUserController
- mUserController.startUser(TEST_USER_ID, true);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
int oldUserId = reportMsg.arg1;
@@ -511,7 +515,8 @@ public class UserControllerTest {
public void testExplicitSystemUserStartInBackground() {
setUpUser(UserHandle.USER_SYSTEM, 0);
assertFalse(mUserController.isSystemUserStarted());
- assertTrue(mUserController.startUser(UserHandle.USER_SYSTEM, false, null));
+ assertTrue(mUserController.startUser(UserHandle.USER_SYSTEM, USER_START_MODE_BACKGROUND,
+ null));
assertTrue(mUserController.isSystemUserStarted());
}
@@ -662,7 +667,7 @@ public class UserControllerTest {
@Test
public void testStopUser_currentUser() {
setUpUser(TEST_USER_ID1, /* flags= */ 0);
- mUserController.startUser(TEST_USER_ID1, /* foreground= */ true);
+ mUserController.startUser(TEST_USER_ID1, USER_START_MODE_FOREGROUND);
int r = mUserController.stopUser(TEST_USER_ID1, /* force= */ true,
/* allowDelayedLocking= */ true, /* stopUserCallback= */ null,
@@ -701,7 +706,7 @@ public class UserControllerTest {
public void testUserNotUnlockedBeforeAllowed() throws Exception {
mUserController.setAllowUserUnlocking(false);
- mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND);
verify(mInjector.mStorageManagerMock, never())
.unlockUserKey(eq(TEST_USER_ID), anyInt(), any());
@@ -862,10 +867,10 @@ public class UserControllerTest {
setUpUser(user1, 0);
setUpUser(user2, 0);
- mUserController.startUser(user1, /* foreground= */ true);
+ mUserController.startUser(user1, USER_START_MODE_FOREGROUND);
mUserController.getStartedUserState(user1).setState(UserState.STATE_RUNNING_UNLOCKED);
- mUserController.startUser(user2, /* foreground= */ false);
+ mUserController.startUser(user2, USER_START_MODE_BACKGROUND);
mUserController.getStartedUserState(user2).setState(UserState.STATE_RUNNING_LOCKED);
final int event1a = SystemService.UserCompletedEventType.EVENT_TYPE_USER_STARTING;
@@ -902,7 +907,7 @@ public class UserControllerTest {
private void setUpAndStartUserInBackground(int userId) throws Exception {
setUpUser(userId, 0);
- mUserController.startUser(userId, /* foreground= */ false);
+ mUserController.startUser(userId, USER_START_MODE_BACKGROUND);
verify(mInjector.mLockPatternUtilsMock, times(1)).unlockUserKeyIfUnsecured(userId);
mUserStates.put(userId, mUserController.getStartedUserState(userId));
}
@@ -946,7 +951,7 @@ public class UserControllerTest {
private void addForegroundUserAndContinueUserSwitch(int newUserId, int expectedOldUserId,
int expectedNumberOfCalls, boolean expectOldUserStopping) {
// Start user -- this will update state of mUserController
- mUserController.startUser(newUserId, true);
+ mUserController.startUser(newUserId, USER_START_MODE_FOREGROUND);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -1005,12 +1010,12 @@ public class UserControllerTest {
private void verifyUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
verify(mInjector.getUserManagerInternal()).assignUserToDisplayOnStart(eq(userId), anyInt(),
- anyBoolean(), eq(displayId));
+ anyInt(), eq(displayId));
}
private void verifyUserNeverAssignedToDisplay() {
verify(mInjector.getUserManagerInternal(), never()).assignUserToDisplayOnStart(anyInt(),
- anyInt(), anyBoolean(), anyInt());
+ anyInt(), anyInt(), anyInt());
}
private void verifyUserUnassignedFromDisplay(@UserIdInt int userId) {
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
index 663017890b0c..47fdcb633352 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
@@ -64,12 +64,12 @@ public class AppOpsNotedWatcherTest {
// Verify that we got called for the ops being noted
final InOrder inOrder = inOrder(listener);
inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
- .times(1)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION),
+ .times(1)).onOpNoted(eq(AppOpsManager.OPSTR_FINE_LOCATION),
eq(Process.myUid()), eq(getContext().getPackageName()),
eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
eq(AppOpsManager.MODE_ALLOWED));
inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
- .times(1)).onOpNoted(eq(AppOpsManager.OP_CAMERA),
+ .times(1)).onOpNoted(eq(AppOpsManager.OPSTR_CAMERA),
eq(Process.myUid()), eq(getContext().getPackageName()),
eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
eq(AppOpsManager.MODE_ALLOWED));
@@ -94,7 +94,7 @@ public class AppOpsNotedWatcherTest {
// Verify it's watched again
verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
- .times(2)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION),
+ .times(2)).onOpNoted(eq(AppOpsManager.OPSTR_FINE_LOCATION),
eq(Process.myUid()), eq(getContext().getPackageName()),
eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
eq(AppOpsManager.MODE_ALLOWED));
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index d2cf15971335..62ef52316f5b 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.companion.virtual;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_INVALID;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
@@ -47,7 +49,6 @@ import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDeviceActivityListener;
-import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
@@ -179,6 +180,7 @@ public class VirtualDeviceManagerServiceTest {
private AssociationInfo mAssociationInfo;
private VirtualDeviceManagerService mVdms;
private VirtualDeviceManagerInternal mLocalService;
+ private VirtualDeviceManagerService.VirtualDeviceManagerImpl mVdm;
@Mock
private InputController.NativeWrapper mNativeWrapperMock;
@Mock
@@ -304,80 +306,68 @@ public class VirtualDeviceManagerServiceTest {
mVdms = new VirtualDeviceManagerService(mContext);
mLocalService = mVdms.getLocalServiceInstance();
+ mVdm = mVdms.new VirtualDeviceManagerImpl();
- mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID);
+ VirtualDeviceParams params = new VirtualDeviceParams
+ .Builder()
+ .setBlockedActivities(getBlockedActivities())
+ .build();
+ mDeviceImpl = new VirtualDeviceImpl(mContext,
+ mAssociationInfo, new Binder(), /* ownerUid= */ 0, VIRTUAL_DEVICE_ID,
+ mInputController, mSensorController, (int associationId) -> {},
+ mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback, params);
+ mVdms.addVirtualDevice(mDeviceImpl);
}
@Test
public void getDeviceIdForDisplayId_invalidDisplayId_returnsDefault() {
- VirtualDeviceManagerService.VirtualDeviceManagerImpl vdm =
- mVdms.new VirtualDeviceManagerImpl();
-
- assertThat(
- vdm.getDeviceIdForDisplayId(Display.INVALID_DISPLAY))
- .isEqualTo(VirtualDeviceManager.DEFAULT_DEVICE_ID);
+ assertThat(mVdm.getDeviceIdForDisplayId(Display.INVALID_DISPLAY))
+ .isEqualTo(DEVICE_ID_DEFAULT);
}
@Test
public void getDeviceIdForDisplayId_defaultDisplayId_returnsDefault() {
- VirtualDeviceManagerService.VirtualDeviceManagerImpl vdm =
- mVdms.new VirtualDeviceManagerImpl();
-
- assertThat(
- vdm.getDeviceIdForDisplayId(Display.DEFAULT_DISPLAY))
- .isEqualTo(VirtualDeviceManager.DEFAULT_DEVICE_ID);
+ assertThat(mVdm.getDeviceIdForDisplayId(Display.DEFAULT_DISPLAY))
+ .isEqualTo(DEVICE_ID_DEFAULT);
}
@Test
public void getDeviceIdForDisplayId_nonExistentDisplayId_returnsDefault() {
- VirtualDeviceManagerService.VirtualDeviceManagerImpl vdm =
- mVdms.new VirtualDeviceManagerImpl();
- int nonExistentDisplayId = 999;
+ mDeviceImpl.mVirtualDisplayIds.remove(DISPLAY_ID);
- assertThat(
- vdm.getDeviceIdForDisplayId(nonExistentDisplayId))
- .isEqualTo(VirtualDeviceManager.DEFAULT_DEVICE_ID);
+ assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID))
+ .isEqualTo(DEVICE_ID_DEFAULT);
}
@Test
public void getDeviceIdForDisplayId_withValidVirtualDisplayId_returnsDeviceId() {
- VirtualDeviceManagerService.VirtualDeviceManagerImpl vdm =
- mVdms.new VirtualDeviceManagerImpl();
- VirtualDeviceImpl virtualDevice = createVirtualDevice(/* virtualDeviceId */ 1000);
- virtualDevice.mVirtualDisplayIds.add(DISPLAY_ID);
+ mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
- assertThat(
- vdm.getDeviceIdForDisplayId(DISPLAY_ID))
- .isEqualTo(1000);
+ assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID))
+ .isEqualTo(mDeviceImpl.getDeviceId());
}
@Test
public void getDevicePolicy_invalidDeviceId_returnsDefault() {
- assertThat(
- mLocalService.getDevicePolicy(
- VirtualDeviceManager.INVALID_DEVICE_ID, POLICY_TYPE_SENSORS))
+ assertThat(mVdm.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@Test
public void getDevicePolicy_defaultDeviceId_returnsDefault() {
- assertThat(
- mLocalService.getDevicePolicy(
- VirtualDeviceManager.DEFAULT_DEVICE_ID, POLICY_TYPE_SENSORS))
+ assertThat(mVdm.getDevicePolicy(DEVICE_ID_DEFAULT, POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@Test
public void getDevicePolicy_nonExistentDeviceId_returnsDefault() {
- assertThat(
- mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
+ assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@Test
public void getDevicePolicy_unspecifiedPolicy_returnsDefault() {
- assertThat(
- mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
+ assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@@ -394,8 +384,7 @@ public class VirtualDeviceManagerServiceTest {
mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback, params);
mVdms.addVirtualDevice(mDeviceImpl);
- assertThat(
- mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
+ assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_CUSTOM);
}
@@ -1196,18 +1185,4 @@ public class VirtualDeviceManagerServiceTest {
verify(mContext).startActivityAsUser(argThat(intent ->
intent.filterEquals(blockedAppIntent)), any(), any());
}
-
- private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId) {
- VirtualDeviceParams params = new VirtualDeviceParams
- .Builder()
- .setBlockedActivities(getBlockedActivities())
- .build();
- VirtualDeviceImpl virtualDeviceImpl = new VirtualDeviceImpl(mContext,
- mAssociationInfo, new Binder(), /* ownerUid */ 0, virtualDeviceId,
- mInputController, mSensorController, (int associationId) -> {},
- mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback, params);
- mVdms.addVirtualDevice(virtualDeviceImpl);
- return virtualDeviceImpl;
- }
-
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index f6f13392ce3a..f47308637a9c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -16,8 +16,8 @@
package com.android.server.companion.virtual;
-import static android.companion.virtual.VirtualDeviceManager.DEFAULT_DEVICE_ID;
-import static android.companion.virtual.VirtualDeviceManager.INVALID_DEVICE_ID;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
+import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_INVALID;
import static com.google.common.truth.Truth.assertThat;
@@ -41,14 +41,14 @@ public class VirtualDeviceTest {
public void build_invalidId_shouldThrowIllegalArgumentException() {
assertThrows(
IllegalArgumentException.class,
- () -> new VirtualDevice(INVALID_DEVICE_ID, VIRTUAL_DEVICE_NAME));
+ () -> new VirtualDevice(DEVICE_ID_INVALID, VIRTUAL_DEVICE_NAME));
}
@Test
public void build_defaultId_shouldThrowIllegalArgumentException() {
assertThrows(
IllegalArgumentException.class,
- () -> new VirtualDevice(DEFAULT_DEVICE_ID, VIRTUAL_DEVICE_NAME));
+ () -> new VirtualDevice(DEVICE_ID_DEFAULT, VIRTUAL_DEVICE_NAME));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 88314ab86c28..a55b19688af3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -7730,9 +7730,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
- assertThat(dpm.getDeviceOwnerType(admin1)).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+ assertThat(dpm.isFinancedDevice()).isTrue();
initializeDpms();
- assertThat(dpm.getDeviceOwnerType(admin1)).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+ assertThat(dpm.isFinancedDevice()).isTrue();
}
@Test
@@ -7743,19 +7743,12 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
- assertThat(dpm.getDeviceOwnerType(admin1)).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+ assertThat(dpm.isFinancedDevice()).isTrue();
}
@Test
- public void testGetDeviceOwnerType_throwsExceptionWhenThereIsNoDeviceOwner() {
- assertThrows(IllegalStateException.class, () -> dpm.getDeviceOwnerType(admin1));
- }
-
- @Test
- public void testGetDeviceOwnerType_throwsExceptionWhenNotAsDeviceOwnerAdmin() throws Exception {
- setDeviceOwner();
-
- assertThrows(IllegalStateException.class, () -> dpm.getDeviceOwnerType(admin2));
+ public void testIsFinancedDevice_throwsExceptionWhenThereIsNoDeviceOwner() {
+ assertThrows(SecurityException.class, () -> dpm.isFinancedDevice());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index d540734d0938..1779b16a7471 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -33,6 +33,7 @@ import android.content.pm.ApplicationInfo;
import android.os.IpcDataCache;
import android.os.Parcel;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
@@ -47,29 +48,42 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.function.Function;
+import javax.xml.parsers.DocumentBuilderFactory;
+
@RunWith(JUnit4.class)
public class PolicyVersionUpgraderTest extends DpmTestBase {
// NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade
// to the new version.
- private static final int LATEST_TESTED_VERSION = 3;
+ private static final int LATEST_TESTED_VERSION = 4;
public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions";
public static final String DEVICE_OWNER_XML = "device_owner_2.xml";
private ComponentName mFakeAdmin;
private class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider {
Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>();
+ ArrayList<String> mPlatformSuspendedPackages = new ArrayList<>();
int[] mUsers;
private JournaledFile makeJournaledFile(int userId, String fileName) {
@@ -98,6 +112,11 @@ public class PolicyVersionUpgraderTest extends DpmTestBase {
public int[] getUsersForUpgrade() {
return mUsers;
}
+
+ @Override
+ public List<String> getPlatformSuspendedPackages(int userId) {
+ return mPlatformSuspendedPackages;
+ }
}
private final Context mRealTestContext = InstrumentationRegistry.getTargetContext();
@@ -257,10 +276,71 @@ public class PolicyVersionUpgraderTest extends DpmTestBase {
}
@Test
+ public void testAdminPackageSuspensionSaved() throws Exception {
+ final int ownerUser = 0;
+ mProvider.mUsers = new int[]{ownerUser};
+ getServices().addUser(ownerUser, FLAG_PRIMARY, USER_TYPE_FULL_SYSTEM);
+ setUpPackageManagerForAdmin(admin1, UserHandle.getUid(ownerUser, 123 /* admin app ID */));
+ writeVersionToXml(3);
+ preparePoliciesFile(ownerUser, "device_policies.xml");
+ prepareDeviceOwnerFile(ownerUser, "device_owner_2.xml");
+
+ // Pretend package manager thinks these packages are suspended by the platform.
+ Set<String> suspendedPkgs = Set.of("com.some.app", "foo.bar.baz");
+ mProvider.mPlatformSuspendedPackages.addAll(suspendedPkgs);
+
+ mUpgrader.upgradePolicy(4);
+
+ assertThat(readVersionFromXml()).isAtLeast(4);
+
+ assertAdminSuspendedPackages(ownerUser, suspendedPkgs);
+ }
+
+ private void assertAdminSuspendedPackages(int ownerUser, Set<String> suspendedPkgs)
+ throws Exception {
+ Document policies = readPolicies(ownerUser);
+ Element adminElem =
+ (Element) policies.getDocumentElement().getElementsByTagName("admin").item(0);
+ Element suspendedElem =
+ (Element) adminElem.getElementsByTagName("suspended-packages").item(0);
+ NodeList pkgsNodes = suspendedElem.getElementsByTagName("item");
+ Set<String> storedSuspendedPkgs = new ArraySet<>();
+ for (int i = 0; i < pkgsNodes.getLength(); i++) {
+ Element item = (Element) pkgsNodes.item(i);
+ storedSuspendedPkgs.add(item.getAttribute("value"));
+ }
+ assertThat(storedSuspendedPkgs).isEqualTo(suspendedPkgs);
+ }
+
+ @Test
public void isLatestVersionTested() {
assertThat(DevicePolicyManagerService.DPMS_VERSION).isEqualTo(LATEST_TESTED_VERSION);
}
+ /**
+ * Reads ABX binary XML, converts it to text, and returns as an input stream.
+ */
+ private InputStream abxToXmlStream(File file) throws Exception {
+ FileInputStream fileIn = new FileInputStream(file);
+ XmlPullParser in = Xml.newBinaryPullParser();
+ in.setInput(fileIn, StandardCharsets.UTF_8.name());
+
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ XmlSerializer out = Xml.newSerializer();
+ out.setOutput(byteOut, StandardCharsets.UTF_8.name());
+
+ Xml.copy(in, out);
+ out.flush();
+
+ return new ByteArrayInputStream(byteOut.toByteArray());
+ }
+
+ private Document readPolicies(int userId) throws Exception {
+ File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead();
+ InputStream is = abxToXmlStream(policiesFile);
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
+ }
+
private void writeVersionToXml(int dpmsVersion) throws IOException {
JournaledFile versionFile = mProvider.makePoliciesVersionJournaledFile(0);
Files.asCharSink(versionFile.chooseForWrite(), Charset.defaultCharset()).write(
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index fdb78b83e493..c1eafd9e35a6 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -145,6 +145,16 @@ public final class DisplayDeviceConfigTest {
assertArrayEquals(new float[]{23, 24, 25},
mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(), ZERO_DELTA);
+ assertEquals(75, mDisplayDeviceConfig.getDefaultLowRefreshRate());
+ assertEquals(90, mDisplayDeviceConfig.getDefaultHighRefreshRate());
+ assertArrayEquals(new int[]{45, 55},
+ mDisplayDeviceConfig.getLowDisplayBrightnessThresholds());
+ assertArrayEquals(new int[]{50, 60},
+ mDisplayDeviceConfig.getLowAmbientBrightnessThresholds());
+ assertArrayEquals(new int[]{65, 75},
+ mDisplayDeviceConfig.getHighDisplayBrightnessThresholds());
+ assertArrayEquals(new int[]{70, 80},
+ mDisplayDeviceConfig.getHighAmbientBrightnessThresholds());
// Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
@@ -207,8 +217,8 @@ public final class DisplayDeviceConfigTest {
mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle(), ZERO_DELTA);
assertArrayEquals(new float[]{29, 30, 31},
mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(), ZERO_DELTA);
- assertEquals(mDisplayDeviceConfig.getDefaultRefreshRate(), DEFAULT_REFRESH_RATE);
- assertEquals(mDisplayDeviceConfig.getDefaultPeakRefreshRate(), DEFAULT_PEAK_REFRESH_RATE);
+ assertEquals(mDisplayDeviceConfig.getDefaultLowRefreshRate(), DEFAULT_REFRESH_RATE);
+ assertEquals(mDisplayDeviceConfig.getDefaultHighRefreshRate(), DEFAULT_PEAK_REFRESH_RATE);
assertArrayEquals(mDisplayDeviceConfig.getLowDisplayBrightnessThresholds(),
LOW_BRIGHTNESS_THRESHOLD_OF_PEAK_REFRESH_RATE);
assertArrayEquals(mDisplayDeviceConfig.getLowAmbientBrightnessThresholds(),
@@ -416,6 +426,38 @@ public final class DisplayDeviceConfigTest {
+ "</brightnessThrottlingPoint>\n"
+ "</brightnessThrottlingMap>\n"
+ "</thermalThrottling>\n"
+ + "<refreshRate>\n"
+ + "<lowerBlockingZoneConfigs>\n"
+ + "<defaultRefreshRate>75</defaultRefreshRate>\n"
+ + "<blockingZoneThreshold>\n"
+ + "<displayBrightnessPoint>\n"
+ + "<lux>50</lux>\n"
+ // This number will be rounded to integer when read by the system
+ + "<nits>45.3</nits>\n"
+ + "</displayBrightnessPoint>\n"
+ + "<displayBrightnessPoint>\n"
+ + "<lux>60</lux>\n"
+ // This number will be rounded to integer when read by the system
+ + "<nits>55.2</nits>\n"
+ + "</displayBrightnessPoint>\n"
+ + "</blockingZoneThreshold>\n"
+ + "</lowerBlockingZoneConfigs>\n"
+ + "<higherBlockingZoneConfigs>\n"
+ + "<defaultRefreshRate>90</defaultRefreshRate>\n"
+ + "<blockingZoneThreshold>\n"
+ + "<displayBrightnessPoint>\n"
+ + "<lux>70</lux>\n"
+ // This number will be rounded to integer when read by the system
+ + "<nits>65.6</nits>\n"
+ + "</displayBrightnessPoint>\n"
+ + "<displayBrightnessPoint>\n"
+ + "<lux>80</lux>\n"
+ // This number will be rounded to integer when read by the system
+ + "<nits>75</nits>\n"
+ + "</displayBrightnessPoint>\n"
+ + "</blockingZoneThreshold>\n"
+ + "</higherBlockingZoneConfigs>\n"
+ + "</refreshRate>\n"
+ "</displayConfiguration>\n";
}
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 865bc987cb2c..bd4058a86b56 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -2250,8 +2250,8 @@ public class DisplayModeDirectorTest {
// Notify that the default display is updated, such that DisplayDeviceConfig has new values
DisplayDeviceConfig displayDeviceConfig = mock(DisplayDeviceConfig.class);
- when(displayDeviceConfig.getDefaultRefreshRate()).thenReturn(50);
- when(displayDeviceConfig.getDefaultPeakRefreshRate()).thenReturn(55);
+ when(displayDeviceConfig.getDefaultLowRefreshRate()).thenReturn(50);
+ when(displayDeviceConfig.getDefaultHighRefreshRate()).thenReturn(55);
when(displayDeviceConfig.getLowDisplayBrightnessThresholds()).thenReturn(new int[]{25});
when(displayDeviceConfig.getLowAmbientBrightnessThresholds()).thenReturn(new int[]{30});
when(displayDeviceConfig.getHighDisplayBrightnessThresholds()).thenReturn(new int[]{210});
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
index 426b9433492d..4b318de78827 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
@@ -25,8 +25,16 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.IContentProvider;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -35,6 +43,9 @@ import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import android.os.Parcel;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IntArray;
@@ -1214,6 +1225,42 @@ public class InputMethodUtilsTest {
StartInputFlags.VIEW_HAS_FOCUS | StartInputFlags.IS_TEXT_EDITOR));
}
+ @Test
+ public void testInputMethodSettings_SwitchCurrentUser() {
+ TestContext ownerUserContext = createMockContext(0 /* userId */);
+ final InputMethodInfo systemIme = createFakeInputMethodInfo(
+ "SystemIme", "fake.latin", true /* isSystem */);
+ final InputMethodInfo nonSystemIme = createFakeInputMethodInfo("NonSystemIme",
+ "fake.voice0", false /* isSystem */);
+ final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+ methodMap.put(systemIme.getId(), systemIme);
+
+ // Init InputMethodSettings for the owner user (userId=0), verify calls can get the
+ // corresponding user's context, contentResolver and the resources configuration.
+ InputMethodUtils.InputMethodSettings settings = new InputMethodUtils.InputMethodSettings(
+ ownerUserContext, methodMap, 0 /* userId */, true);
+ assertEquals(0, settings.getCurrentUserId());
+
+ settings.isShowImeWithHardKeyboardEnabled();
+ verify(ownerUserContext.getContentResolver(), atLeastOnce()).getAttributionSource();
+
+ settings.getEnabledInputMethodSubtypeListLocked(nonSystemIme, true);
+ verify(ownerUserContext.getResources(), atLeastOnce()).getConfiguration();
+
+ // Calling switchCurrentUser to the secondary user (userId=10), verify calls can get the
+ // corresponding user's context, contentResolver and the resources configuration.
+ settings.switchCurrentUser(10 /* userId */, true);
+ assertEquals(10, settings.getCurrentUserId());
+
+ settings.isShowImeWithHardKeyboardEnabled();
+ verify(TestContext.getSecondaryUserContext().getContentResolver(),
+ atLeastOnce()).getAttributionSource();
+
+ settings.getEnabledInputMethodSubtypeListLocked(nonSystemIme, true);
+ verify(TestContext.getSecondaryUserContext().getResources(),
+ atLeastOnce()).getConfiguration();
+ }
+
private static IntArray createSubtypeHashCodeArrayFromStr(String subtypeHashCodesStr) {
final IntArray subtypes = new IntArray();
final TextUtils.SimpleStringSplitter imeSubtypeSplitter =
@@ -1236,6 +1283,63 @@ public class InputMethodUtilsTest {
imeId, createSubtypeHashCodeArrayFromStr(enabledSubtypeHashCodesStr)));
}
+ private static TestContext createMockContext(int userId) {
+ return new TestContext(InstrumentationRegistry.getInstrumentation()
+ .getTargetContext(), userId);
+ }
+
+ private static class TestContext extends ContextWrapper {
+ private int mUserId;
+ private ContentResolver mResolver;
+ private Resources mResources;
+
+ private static TestContext sSecondaryUserContext;
+
+ TestContext(@NonNull Context context, int userId) {
+ super(context);
+ mUserId = userId;
+ mResolver = mock(MockContentResolver.class);
+ when(mResolver.acquireProvider(Settings.Secure.CONTENT_URI)).thenReturn(
+ mock(IContentProvider.class));
+ mResources = mock(Resources.class);
+
+ final Configuration configuration = new Configuration();
+ if (userId == 0) {
+ configuration.setLocale(LOCALE_EN_US);
+ } else {
+ configuration.setLocale(LOCALE_FR_CA);
+ }
+ doReturn(configuration).when(mResources).getConfiguration();
+ }
+
+ @Override
+ public Context createContextAsUser(UserHandle user, int flags) {
+ if (user.getIdentifier() != UserHandle.USER_SYSTEM) {
+ return sSecondaryUserContext = new TestContext(this, user.getIdentifier());
+ }
+ return this;
+ }
+
+ @Override
+ public int getUserId() {
+ return mUserId;
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mResolver;
+ }
+
+ @Override
+ public Resources getResources() {
+ return mResources;
+ }
+
+ static Context getSecondaryUserContext() {
+ return sSecondaryUserContext;
+ }
+ }
+
@Test
public void updateEnabledImeStringTest() {
// No change cases
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index 3848babdc912..57f9f1831304 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -30,8 +30,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.hardware.thermal.V2_0.TemperatureThreshold;
-import android.hardware.thermal.V2_0.ThrottlingSeverity;
+import android.hardware.thermal.TemperatureThreshold;
+import android.hardware.thermal.ThrottlingSeverity;
import android.os.CoolingDevice;
import android.os.IBinder;
import android.os.IPowerManager;
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 92c7871e611d..16c213c77d10 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -405,12 +405,11 @@ public class SystemConfigTest {
mSysConfig.readApexPrivAppPermissions(parser, permissionFile, apexDir.toPath());
- assertThat(mSysConfig.getApexPrivAppPermissions("com.android.my_module",
- "com.android.apk_in_apex"))
- .containsExactly("android.permission.FOO");
- assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.my_module",
- "com.android.apk_in_apex"))
- .containsExactly("android.permission.BAR");
+ ArrayMap<String, Boolean> permissions = mSysConfig.getPermissionAllowlist()
+ .getApexPrivilegedAppAllowlists().get("com.android.my_module")
+ .get("com.android.apk_in_apex");
+ assertThat(permissions)
+ .containsExactly("android.permission.FOO", true, "android.permission.BAR", false);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index f983fa9b49e3..982137b00bfc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3284,7 +3284,7 @@ public class ActivityRecordTests extends WindowTestsBase {
assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
verify(app2.mClient, atLeastOnce()).resized(any(), anyBoolean(), any(),
insetsStateCaptor.capture(), anyBoolean(), anyBoolean(), anyInt(), anyInt(),
- anyInt());
+ anyBoolean());
assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ee31748e24c7..d16e11ba6398 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -62,11 +62,13 @@ import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.server.wm.WindowTestsBase.ActivityBuilder.DEFAULT_FAKE_UID;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -1617,6 +1619,119 @@ public class ActivityStarterTests extends WindowTestsBase {
assertNull(starter2.mMovedToTopActivity);
}
+ /**
+ * Tests a task with specific display category exist in system and then launching another
+ * activity with the same affinity but without define the display category. Make sure the
+ * lunching activity is placed on the different task.
+ */
+ @Test
+ public void testLaunchActivityWithoutDisplayCategory() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID,
+ 0 /* launchMode */);
+ info.requiredDisplayCategory = "automotive";
+ final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
+ .build();
+
+ final ActivityRecord target = new ActivityBuilder(mAtm).setAffinity(info.taskAffinity)
+ .build();
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, false);
+ startActivityInner(starter, target, null /* source */, null /* options */,
+ null /* inTask */, null /* inTaskFragment */);
+
+ assertNotEquals(task, target.getTask());
+ }
+
+ /**
+ * Tests a task with a specific display category exist in the system and then launches another
+ * activity with the different display category. Make sure the launching activity is not placed
+ * on the sourceRecord's task.
+ */
+ @Test
+ public void testLaunchActivityWithDifferentDisplayCategory() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID,
+ 0 /* launchMode */);
+ info.requiredDisplayCategory = "automotive";
+ final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
+ .build();
+
+ final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto")
+ .setAffinity(info.taskAffinity).build();
+ final ActivityStarter starter = prepareStarter(0, false);
+ startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */,
+ null /* inTask */, null /* inTaskFragment */);
+
+ assertNotEquals(task, target.getTask());
+ }
+
+ /**
+ * Tests a task with specific display category exist in system and then launching another
+ * activity with the same display category. Make sure the launching activity is placed on the
+ * same task.
+ */
+ @Test
+ public void testLaunchActivityWithSameDisplayCategory() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID,
+ 0 /* launchMode */);
+ info.requiredDisplayCategory = "automotive";
+ final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
+ .build();
+
+ final ActivityRecord target = new ActivityBuilder(mAtm)
+ .setRequiredDisplayCategory(info.requiredDisplayCategory)
+ .setAffinity(info.taskAffinity).build();
+ final ActivityStarter starter = prepareStarter(0, false);
+ startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */,
+ null /* inTask */, null /* inTaskFragment */);
+
+ assertEquals(task, target.getTask());
+ }
+
+ /**
+ * Tests a task with specific display category exist in system and launching activity into the
+ * specific task within inTask attribute. Make sure the activity is not placed on the task since
+ * the display category is different.
+ */
+ @Test
+ public void testLaunchActivityInTaskWithDisplayCategory() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.requiredDisplayCategory = "automotive";
+ final Task inTask = new TaskBuilder(mSupervisor).setActivityInfo(info).build();
+ inTask.inRecents = true;
+
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord target = new ActivityBuilder(mAtm).build();
+ startActivityInner(starter, target, null /* source */, null /* options */, inTask,
+ null /* inTaskFragment */);
+
+ assertNotEquals(inTask, target.getTask());
+ }
+
+ /**
+ * Tests a task without a specific display category exist in the system and launches activity
+ * with display category into the task within the inTask attribute. Make sure the activity is
+ * not placed on the task since the display category is different.
+ */
+ @Test
+ public void testLaunchDisplayCategoryActivityInTask() {
+ final Task inTask = new TaskBuilder(mSupervisor).build();
+ inTask.inRecents = true;
+
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto")
+ .build();
+ startActivityInner(starter, target, null /* source */, null /* options */, inTask,
+ null /* inTaskFragment */);
+
+ assertNotEquals(inTask, target.getTask());
+ }
+
private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
ActivityRecord source, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index fd2a1d1c352f..c7971bc7911f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -37,6 +37,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -46,7 +48,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.StatusBarManager;
@@ -265,7 +266,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
final WindowState navBar = addNavigationBar();
navBar.setHasSurface(true);
navBar.getControllableInsetProvider().setServerVisible(true);
- final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
+ final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
+ spyOn(policy);
doNothing().when(policy).startAnimation(anyBoolean(), any());
// Make both system bars invisible.
@@ -302,12 +304,15 @@ public class InsetsPolicyTest extends WindowTestsBase {
addStatusBar().getControllableInsetProvider().getSource().setVisible(false);
addNavigationBar().getControllableInsetProvider().setServerVisible(true);
- final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
+ final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
+ spyOn(policy);
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(mAppWindow);
policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR},
true /* isGestureOnSystemBar */);
waitUntilWindowAnimatorIdle();
+ assertTrue(policy.isTransient(ITYPE_STATUS_BAR));
+ assertFalse(policy.isTransient(ITYPE_NAVIGATION_BAR));
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -335,7 +340,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
navBarSource.setVisible(false);
mAppWindow.mAboveInsetsState.addSource(navBarSource);
mAppWindow.mAboveInsetsState.addSource(statusBarSource);
- final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
+ final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
+ spyOn(policy);
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(mAppWindow);
policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR},
@@ -383,7 +389,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
final WindowState app = addWindow(TYPE_APPLICATION, "app");
final WindowState app2 = addWindow(TYPE_APPLICATION, "app");
- final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
+ final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
+ spyOn(policy);
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(app);
policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR},
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index c333c93eaea2..d5c15794cc28 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -19,9 +19,16 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
-import static android.window.TaskFragmentOrganizer.getTransitionType;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CLOSE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_NONE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN;
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
@@ -583,7 +590,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
mTransaction.startActivityInTaskFragment(
mFragmentToken, ownerActivity.token, new Intent(), null /* activityOptions */);
- mOrganizer.applyTransaction(mTransaction);
+ mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_OPEN,
+ false /* shouldApplyIndependently */);
// Not allowed because TaskFragment is not organized by the caller organizer.
assertApplyTransactionDisallowed(mTransaction);
@@ -604,7 +612,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.build();
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
- mOrganizer.applyTransaction(mTransaction);
+ mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
// Not allowed because TaskFragment is not organized by the caller organizer.
assertApplyTransactionDisallowed(mTransaction);
@@ -630,7 +639,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.build();
mWindowOrganizerController.mLaunchTaskFragments.put(fragmentToken2, taskFragment2);
mTransaction.setAdjacentTaskFragments(mFragmentToken, fragmentToken2, null /* params */);
- mOrganizer.applyTransaction(mTransaction);
+ mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
// Not allowed because TaskFragments are not organized by the caller organizer.
assertApplyTransactionDisallowed(mTransaction);
@@ -663,7 +673,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.build();
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
mTransaction.requestFocusOnTaskFragment(mFragmentToken);
- mOrganizer.applyTransaction(mTransaction);
+ mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
// Not allowed because TaskFragment is not organized by the caller organizer.
assertApplyTransactionDisallowed(mTransaction);
@@ -765,7 +776,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final ActivityRecord activity = createActivityRecord(task);
// Skip manipulate the SurfaceControl.
doNothing().when(activity).setDropInputMode(anyInt());
- mOrganizer.applyTransaction(mTransaction);
+ mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
.setFragmentToken(mFragmentToken)
@@ -866,8 +878,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
- mController.onTransactionHandled(new Binder(), mTransaction,
- getTransitionType(mTransaction), false /* shouldApplyIndependently */);
+ mController.onTransactionHandled(new Binder(), mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
// Nothing should happen as the organizer is not registered.
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
@@ -1415,12 +1427,31 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final IBinder transactionToken = tokenCaptor.getValue();
final WindowContainerTransaction wct = wctCaptor.getValue();
wct.setTaskFragmentOrganizer(mIOrganizer);
- mController.onTransactionHandled(transactionToken, wct, getTransitionType(wct),
+ mController.onTransactionHandled(transactionToken, wct, TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */);
verify(mTransitionController).continueTransitionReady();
}
+ @Test
+ public void testWindowOrganizerApplyTransaction_throwException() {
+ // Not allow to use #applyTransaction(WindowContainerTransaction).
+ assertThrows(RuntimeException.class, () -> mOrganizer.applyTransaction(mTransaction));
+
+ // Allow to use the overload method.
+ mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
+ }
+
+ @Test
+ public void testTaskFragmentTransitionType() {
+ // 1-1 relationship with WindowManager.TransitionType
+ assertEquals(TRANSIT_NONE, TASK_FRAGMENT_TRANSIT_NONE);
+ assertEquals(TRANSIT_OPEN, TASK_FRAGMENT_TRANSIT_OPEN);
+ assertEquals(TRANSIT_CLOSE, TASK_FRAGMENT_TRANSIT_CLOSE);
+ assertEquals(TRANSIT_CHANGE, TASK_FRAGMENT_TRANSIT_CHANGE);
+ }
+
/**
* Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
* {@link WindowOrganizerController#applyTransaction(WindowContainerTransaction)} to apply the
@@ -1442,13 +1473,14 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
/** Asserts that applying the given transaction will throw a {@link SecurityException}. */
private void assertApplyTransactionDisallowed(WindowContainerTransaction t) {
assertThrows(SecurityException.class, () ->
- mController.applyTransaction(t, getTransitionType(t),
+ mController.applyTransaction(t, TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */));
}
/** Asserts that applying the given transaction will not throw any exception. */
private void assertApplyTransactionAllowed(WindowContainerTransaction t) {
- mController.applyTransaction(t, getTransitionType(t), false /* shouldApplyIndependently */);
+ mController.applyTransaction(t, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
}
/** Asserts that there will be a transaction for TaskFragment appeared. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 6e72bf360295..3f8acc651110 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -46,7 +46,7 @@ public class TestIWindow extends IWindow.Stub {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfig, InsetsState insetsState, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode)
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing)
throws RemoteException {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 50fcafca5273..98a28cfbe22c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -869,6 +869,28 @@ public class WindowContainerTests extends WindowTestsBase {
}
@Test
+ public void testOnDisplayChanged_cleanupChanging() {
+ final Task task = createTask(mDisplayContent);
+ spyOn(task.mSurfaceFreezer);
+ mDisplayContent.mChangingContainers.add(task);
+
+ // Don't remove the changing transition of this window when it is still the old display.
+ // This happens on display info changed.
+ task.onDisplayChanged(mDisplayContent);
+
+ assertTrue(mDisplayContent.mChangingContainers.contains(task));
+ verify(task.mSurfaceFreezer, never()).unfreeze(any());
+
+ // Remove the changing transition of this window when it is moved or reparented from the old
+ // display.
+ final DisplayContent newDc = createNewDisplay();
+ task.onDisplayChanged(newDc);
+
+ assertFalse(mDisplayContent.mChangingContainers.contains(task));
+ verify(task.mSurfaceFreezer).unfreeze(any());
+ }
+
+ @Test
public void testHandleCompleteDeferredRemoval() {
final DisplayContent displayContent = createNewDisplay();
// Do not reparent activity to default display when removing the display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 69e3244af1b6..183ccceec4f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -276,12 +276,9 @@ public class WindowStateTests extends WindowTestsBase {
assertFalse(imeWindow.canBeImeTarget());
// Simulate the window is in split screen root task.
- final DockedTaskDividerController controller =
- mDisplayContent.getDockedDividerController();
final Task rootTask = createTask(mDisplayContent,
WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
spyOn(appWindow);
- spyOn(controller);
spyOn(rootTask);
rootTask.setFocusable(false);
doReturn(rootTask).when(appWindow).getRootTask();
@@ -775,7 +772,7 @@ public class WindowStateTests extends WindowTestsBase {
anyBoolean() /* reportDraw */, any() /* mergedConfig */,
any() /* insetsState */, anyBoolean() /* forceLayout */,
anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */,
- anyInt() /* seqId */, anyInt() /* resizeMode */);
+ anyInt() /* seqId */, anyBoolean() /* dragResizing */);
} catch (RemoteException ignored) {
}
win.reportResized();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 019b14db161c..4d3141438607 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1017,6 +1017,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
private ActivityInfo.WindowLayout mWindowLayout;
private boolean mVisible = true;
private ActivityOptions mLaunchIntoPipOpts;
+ private String mRequiredDisplayCategory;
ActivityBuilder(ActivityTaskManagerService service) {
mService = service;
@@ -1157,6 +1158,11 @@ class WindowTestsBase extends SystemServiceTestsBase {
return this;
}
+ ActivityBuilder setRequiredDisplayCategory(String requiredDisplayCategory) {
+ mRequiredDisplayCategory = requiredDisplayCategory;
+ return this;
+ }
+
ActivityRecord build() {
SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
try {
@@ -1201,6 +1207,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
aInfo.configChanges |= mConfigChanges;
aInfo.taskAffinity = mAffinity;
aInfo.windowLayout = mWindowLayout;
+ if (mRequiredDisplayCategory != null) {
+ aInfo.requiredDisplayCategory = mRequiredDisplayCategory;
+ }
if (mCreateTask) {
mTask = new TaskBuilder(mService.mTaskSupervisor)
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 1ba997f4c334..fdf694303dbc 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -743,11 +743,23 @@ public final class TelephonyPermissions {
/**
* Given a list of permissions, check to see if the caller has at least one of them granted. If
- * not, check to see if the caller has carrier privileges. If the caller does not have any of
+ * not, check to see if the caller has carrier privileges. If the caller does not have any of
* these permissions, throw a SecurityException.
*/
public static void enforceAnyPermissionGrantedOrCarrierPrivileges(Context context, int subId,
int uid, String message, String... permissions) {
+ enforceAnyPermissionGrantedOrCarrierPrivileges(
+ context, subId, uid, false, message, permissions);
+ }
+
+ /**
+ * Given a list of permissions, check to see if the caller has at least one of them granted. If
+ * not, check to see if the caller has carrier privileges on the specified subscription (or any
+ * subscription if {@code allowCarrierPrivilegeOnAnySub} is {@code true}. If the caller does not
+ * have any of these permissions, throw a {@link SecurityException}.
+ */
+ public static void enforceAnyPermissionGrantedOrCarrierPrivileges(Context context, int subId,
+ int uid, boolean allowCarrierPrivilegeOnAnySub, String message, String... permissions) {
if (permissions.length == 0) return;
boolean isGranted = false;
for (String perm : permissions) {
@@ -758,7 +770,12 @@ public final class TelephonyPermissions {
}
if (isGranted) return;
- if (checkCarrierPrivilegeForSubId(context, subId)) return;
+
+ if (allowCarrierPrivilegeOnAnySub) {
+ if (checkCarrierPrivilegeForAnySubId(context, Binder.getCallingUid())) return;
+ } else {
+ if (checkCarrierPrivilegeForSubId(context, subId)) return;
+ }
StringBuilder b = new StringBuilder(message);
b.append(": Neither user ");
@@ -769,7 +786,8 @@ public final class TelephonyPermissions {
b.append(" or ");
b.append(permissions[i]);
}
- b.append(" or carrier privileges");
+ b.append(" or carrier privileges. subId=" + subId + ", allowCarrierPrivilegeOnAnySub="
+ + allowCarrierPrivilegeOnAnySub);
throw new SecurityException(b.toString());
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 22cd31a39f24..91036587320b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -52,6 +52,7 @@ import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.telephony.Rlog;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -9957,10 +9958,13 @@ public class CarrierConfigManager {
* @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
* @return A {@link PersistableBundle} containing the config for the given subId, or default
* values for an invalid subId.
+ *
+ * @deprecated Use {@link #getConfigForSubId(int, String...)} instead.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
+ @Deprecated
public PersistableBundle getConfigForSubId(int subId) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
@@ -9979,6 +9983,58 @@ public class CarrierConfigManager {
}
/**
+ * Gets the configuration values of the specified keys for a particular subscription.
+ *
+ * <p>If an invalid subId is used, the returned configuration will contain default values for
+ * the specified keys.
+ *
+ * <p>After using this method to get the configuration bundle,
+ * {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be called to confirm whether
+ * any carrier specific configuration has been applied.
+ *
+ * <p>Note that on success, the key/value for {@link #KEY_CARRIER_CONFIG_VERSION_STRING} and
+ * {@link #KEY_CARRIER_CONFIG_APPLIED_BOOL} are always in the returned bundle, no matter if they
+ * were explicitly requested.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges on the specified subscription (see
+ * {@link TelephonyManager#hasCarrierPrivileges()}).
+ *
+ * @param subId The subscription ID on which the carrier config should be retrieved.
+ * @param keys The carrier config keys to retrieve values.
+ * @return A {@link PersistableBundle} with key/value mapping for the specified configuration
+ * on success, or an empty (but never null) bundle on failure (for example, when no value for
+ * the specified key can be found).
+ */
+ @RequiresPermission(anyOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ "carrier privileges",
+ })
+ @NonNull
+ public PersistableBundle getConfigForSubId(int subId, @NonNull String... keys) {
+ Objects.requireNonNull(keys, "Config keys should be non-null");
+ for (String key : keys) {
+ Objects.requireNonNull(key, "Config key should be non-null");
+ }
+
+ try {
+ ICarrierConfigLoader loader = getICarrierConfigLoader();
+ if (loader == null) {
+ Rlog.w(TAG, "Error getting config for subId " + subId
+ + " ICarrierConfigLoader is null");
+ throw new IllegalStateException("Carrier config loader is not available.");
+ }
+ return loader.getConfigSubsetForSubIdWithFeature(subId, mContext.getOpPackageName(),
+ mContext.getAttributionTag(), keys);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "Error getting config for subId " + subId + ": " + ex);
+ ex.rethrowAsRuntimeException();
+ }
+ return new PersistableBundle();
+ }
+
+ /**
* Overrides the carrier config of the provided subscription ID with the provided values.
*
* Any further queries to carrier config from any process will return the overridden values
@@ -10052,15 +10108,50 @@ public class CarrierConfigManager {
* has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
*
* @see #getConfigForSubId
+ * @see #getConfig(String...)
+ * @deprecated use {@link #getConfig(String...)} instead.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
+ @Deprecated
public PersistableBundle getConfig() {
return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
}
/**
+ * Gets the configuration values of the specified config keys applied for the default
+ * subscription.
+ *
+ * <p>After using this method to get the configuration bundle, {@link
+ * #isConfigForIdentifiedCarrier(PersistableBundle)} should be called to confirm whether any
+ * carrier specific configuration has been applied.
+ *
+ * <p>Note that on success, the key/value for {@link #KEY_CARRIER_CONFIG_VERSION_STRING} and
+ * {@link #KEY_CARRIER_CONFIG_APPLIED_BOOL} are always in the returned bundle, no matter if
+ * they were explicitly requested.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges for the default subscription (see
+ * {@link TelephonyManager#hasCarrierPrivileges()}).
+ *
+ * @param keys The config keys to retrieve values
+ * @return A {@link PersistableBundle} with key/value mapping for the specified carrier
+ * configs on success, or an empty (but never null) bundle on failure.
+ * @see #getConfigForSubId(int, String...)
+ * @see SubscriptionManager#getDefaultSubscriptionId()
+ */
+ @RequiresPermission(anyOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ "carrier privileges",
+ })
+ @NonNull
+ public PersistableBundle getConfig(@NonNull String... keys) {
+ return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId(), keys);
+ }
+
+ /**
* Determines whether a configuration {@link PersistableBundle} obtained from
* {@link #getConfig()} or {@link #getConfigForSubId(int)} corresponds to an identified carrier.
*
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 1f301c1b2279..d1f19ee0f1e6 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -3125,6 +3125,43 @@ public final class SmsManager {
}
}
+ /**
+ * Set Storage Availability in SmsStorageMonitor
+ * @param storageAvailable storage availability to be set true or false
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @TestApi
+ public void setStorageMonitorMemoryStatusOverride(boolean storageAvailable) {
+ try {
+ ISms iccISms = getISmsServiceOrThrow();
+ if (iccISms != null) {
+ iccISms.setStorageMonitorMemoryStatusOverride(getSubscriptionId(),
+ storageAvailable);
+ }
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Clear the memory status override set by
+ * {@link #setStorageMonitorMemoryStatusOverride(boolean)}
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @TestApi
+ public void clearStorageMonitorMemoryStatusOverride() {
+ try {
+ ISms iccISms = getISmsServiceOrThrow();
+ if (iccISms != null) {
+ iccISms.clearStorageMonitorMemoryStatusOverride(getSubscriptionId());
+ }
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ }
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"SMS_CATEGORY_"},
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 5244f415e8e2..9b566fbeb0bb 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -754,6 +754,15 @@ public class SubscriptionManager {
/** Indicates that data roaming is disabled for a subscription */
public static final int DATA_ROAMING_DISABLE = SimInfo.DATA_ROAMING_DISABLE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"DATA_ROAMING_"},
+ value = {
+ DATA_ROAMING_ENABLE,
+ DATA_ROAMING_DISABLE
+ })
+ public @interface DataRoamingMode {}
+
/**
* TelephonyProvider column name for subscription carrier id.
* @see TelephonyManager#getSimCarrierId()
@@ -2605,37 +2614,6 @@ public class SubscriptionManager {
}
/**
- * Returns a constant indicating the state of sim for the slot index.
- *
- * @param slotIndex
- *
- * {@See TelephonyManager#SIM_STATE_UNKNOWN}
- * {@See TelephonyManager#SIM_STATE_ABSENT}
- * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED}
- * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED}
- * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED}
- * {@See TelephonyManager#SIM_STATE_READY}
- * {@See TelephonyManager#SIM_STATE_NOT_READY}
- * {@See TelephonyManager#SIM_STATE_PERM_DISABLED}
- * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR}
- *
- * {@hide}
- */
- public static int getSimStateForSlotIndex(int slotIndex) {
- int simState = TelephonyManager.SIM_STATE_UNKNOWN;
-
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- simState = iSub.getSimStateForSlotIndex(slotIndex);
- }
- } catch (RemoteException ex) {
- }
-
- return simState;
- }
-
- /**
* Store properties associated with SubscriptionInfo in database
* @param subId Subscription Id of Subscription
* @param propKey Column name in database associated with SubscriptionInfo
@@ -3726,10 +3704,15 @@ public class SubscriptionManager {
}
/**
- * DO NOT USE.
- * This API is designed for features that are not finished at this point. Do not call this API.
+ * Check if a subscription is active.
+ *
+ * @param subscriptionId The subscription id to check.
+ *
+ * @return {@code true} if the subscription is active.
+ *
+ * @throws IllegalArgumentException if the provided slot index is invalid.
+ *
* @hide
- * TODO b/135547512: further clean up
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -3750,8 +3733,12 @@ public class SubscriptionManager {
* Set the device to device status sharing user preference for a subscription ID. The setting
* app uses this method to indicate with whom they wish to share device to device status
* information.
- * @param sharing the status sharing preference
- * @param subscriptionId the unique Subscription ID in database
+ *
+ * @param subscriptionId the unique Subscription ID in database.
+ * @param sharing the status sharing preference.
+ *
+ * @throws IllegalArgumentException if the subscription does not exist, or the sharing
+ * preference is invalid.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setDeviceToDeviceStatusSharingPreference(int subscriptionId,
@@ -3782,8 +3769,12 @@ public class SubscriptionManager {
* Set the list of contacts that allow device to device status sharing for a subscription ID.
* The setting app uses this method to indicate with whom they wish to share device to device
* status information.
- * @param contacts The list of contacts that allow device to device status sharing
- * @param subscriptionId The unique Subscription ID in database
+ *
+ * @param subscriptionId The unique Subscription ID in database.
+ * @param contacts The list of contacts that allow device to device status sharing.
+ *
+ * @throws IllegalArgumentException if the subscription does not exist, or contacts is
+ * {@code null}.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setDeviceToDeviceStatusSharingContacts(int subscriptionId,
@@ -3813,16 +3804,24 @@ public class SubscriptionManager {
}
/**
- * DO NOT USE.
- * This API is designed for features that are not finished at this point. Do not call this API.
+ * Get the active subscription id by logical SIM slot index.
+ *
+ * @param slotIndex The logical SIM slot index.
+ * @return The active subscription id.
+ *
+ * @throws IllegalArgumentException if the provided slot index is invalid.
+ *
* @hide
- * TODO b/135547512: further clean up
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public int getEnabledSubscriptionId(int slotIndex) {
int subId = INVALID_SUBSCRIPTION_ID;
+ if (!isValidSlotIndex(slotIndex)) {
+ throw new IllegalArgumentException("Invalid slot index " + slotIndex);
+ }
+
try {
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
@@ -3864,12 +3863,12 @@ public class SubscriptionManager {
/**
* Get active data subscription id. Active data subscription refers to the subscription
* currently chosen to provide cellular internet connection to the user. This may be
- * different from getDefaultDataSubscriptionId(). Eg. Opportunistics data
+ * different from getDefaultDataSubscriptionId().
*
- * See {@link PhoneStateListener#onActiveDataSubscriptionIdChanged(int)} for the details.
+ * @return Active data subscription id if any is chosen, or {@link #INVALID_SUBSCRIPTION_ID} if
+ * not.
*
- * @return Active data subscription id if any is chosen, or
- * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not.
+ * @see TelephonyCallback.ActiveDataSubscriptionIdListener
*/
public static int getActiveDataSubscriptionId() {
if (isSubscriptionManagerServiceEnabled()) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3024b896d1cf..c926a23f55ce 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -71,7 +71,6 @@ import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings.SettingNotFoundException;
import android.service.carrier.CarrierIdentifier;
@@ -127,7 +126,6 @@ import com.android.internal.telephony.IccLogicalChannelRequest;
import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.SmsApplication;
import com.android.telephony.Rlog;
import java.io.IOException;
@@ -2937,7 +2935,7 @@ public class TelephonyManager {
public static final int NETWORK_TYPE_HSPA = TelephonyProtoEnums.NETWORK_TYPE_HSPA; // = 10.
/**
* Current network is iDen
- * @deprecated Legacy network type no longer being used.
+ * @deprecated Legacy network type no longer being used starting in Android U.
*/
@Deprecated
public static final int NETWORK_TYPE_IDEN = TelephonyProtoEnums.NETWORK_TYPE_IDEN; // = 11.
@@ -3558,7 +3556,7 @@ public class TelephonyManager {
"state as absent");
return SIM_STATE_ABSENT;
}
- return SubscriptionManager.getSimStateForSlotIndex(slotIndex);
+ return getSimStateForSlotIndex(slotIndex);
}
/**
@@ -3705,9 +3703,7 @@ public class TelephonyManager {
@Deprecated
public @SimState int getSimApplicationState(int physicalSlotIndex) {
int activePort = getFirstActivePortIndex(physicalSlotIndex);
- int simState =
- SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex,
- activePort));
+ int simState = getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, activePort));
return getSimApplicationStateFromSimState(simState);
}
@@ -3733,9 +3729,7 @@ public class TelephonyManager {
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public @SimState int getSimApplicationState(int physicalSlotIndex, int portIndex) {
- int simState =
- SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex,
- portIndex));
+ int simState = getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, portIndex));
return getSimApplicationStateFromSimState(simState);
}
@@ -3804,7 +3798,7 @@ public class TelephonyManager {
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public @SimState int getSimState(int slotIndex) {
- int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex);
+ int simState = getSimStateForSlotIndex(slotIndex);
if (simState == SIM_STATE_LOADED) {
simState = SIM_STATE_READY;
}
@@ -13966,7 +13960,7 @@ public class TelephonyManager {
* If used, will be converted to {@link #NETWORK_TYPE_BITMASK_LTE}.
* network type bitmask indicating the support of radio tech LTE CA (carrier aggregation).
*
- * @deprecated Please use {@link #NETWORK_TYPE_BITMASK_LTE} instead.
+ * @deprecated Please use {@link #NETWORK_TYPE_BITMASK_LTE} instead. Deprecated in Android U.
*/
@Deprecated
public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1));
@@ -17747,4 +17741,84 @@ public class TelephonyManager {
}
return null;
}
+
+ /**
+ * Returns a constant indicating the state of sim for the slot index.
+ *
+ * @param slotIndex Logical SIM slot index.
+ *
+ * @see TelephonyManager.SimState
+ *
+ * @hide
+ */
+ @SimState
+ public static int getSimStateForSlotIndex(int slotIndex) {
+ try {
+ ITelephony telephony = ITelephony.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
+ if (telephony != null) {
+ return telephony.getSimStateForSlotIndex(slotIndex);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in getSimStateForSlotIndex: " + e);
+ }
+ return TelephonyManager.SIM_STATE_UNKNOWN;
+ }
+
+ /**
+ * Set the UE's ability to accept/reject null ciphered and null integrity-protected connections.
+ *
+ * The modem is required to ignore this in case of an emergency call.
+ *
+ * <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE</p>
+ *
+ * @param enabled if null ciphered and null integrity protected connections are permitted
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support disabling null ciphers.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setNullCipherAndIntegrityEnabled(boolean enabled) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setNullCipherAndIntegrityEnabled(enabled);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setNullCipherAndIntegrityEnabled RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the value of the global preference for null cipher and integriy enablement.
+ * Note: This does not return the state of the modem, only the persisted global preference.
+ *
+ * <p>Requires permission: android.Manifest.READ_PHONE_STATE</p>
+ *
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support disabling null ciphers.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public void isNullCipherAndIntegrityPreferenceEnabled() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.isNullCipherAndIntegrityPreferenceEnabled();
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "isNullCipherAndIntegrityPreferenceEnabled RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index fa3f15d0e2ca..554beb9a35ba 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1286,7 +1286,7 @@ public class ApnSetting implements Parcelable {
&& xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
&& xorEqualsString(this.mUser, other.mUser)
&& xorEqualsString(this.mPassword, other.mPassword)
- && xorEqualsInt(this.mAuthType, other.mAuthType)
+ && Objects.equals(this.mAuthType, other.mAuthType)
&& !typeSameAny(this, other)
&& Objects.equals(this.mOperatorNumeric, other.mOperatorNumeric)
&& Objects.equals(this.mProtocol, other.mProtocol)
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a2d20193a430..cdb7d7c9ff59 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -1570,8 +1570,8 @@ public class EuiccManager {
/**
* Returns whether the passing portIndex is available.
- * A port is available if it is active without enabled profile on it or
- * calling app has carrier privilege over the profile installed on the selected port.
+ * A port is available if it is active without an enabled profile on it or calling app can
+ * activate a new profile on the selected port without any user interaction.
* Always returns false if the cardId is a physical card.
*
* @param portIndex is an enumeration of the ports available on the UICC.
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 9996b868afc7..7a800a5be57f 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Binder;
@@ -75,6 +76,41 @@ public interface RegistrationManager {
*/
int REGISTRATION_STATE_REGISTERED = 2;
+ /** @hide */
+ @IntDef(prefix = {"SUGGESTED_ACTION_"},
+ value = {
+ SUGGESTED_ACTION_NONE,
+ SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK,
+ SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SuggestedAction {}
+
+ /**
+ * Default value. No action is suggested when IMS registration fails.
+ * @hide
+ */
+ @SystemApi
+ public static final int SUGGESTED_ACTION_NONE = 0;
+
+ /**
+ * Indicates that the IMS registration is failed with fatal error such as 403 or 404
+ * on all P-CSCF addresses. The radio shall block the current PLMN or disable
+ * the RAT as per the carrier requirements.
+ * @hide
+ */
+ @SystemApi
+ public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK = 1;
+
+ /**
+ * Indicates that the IMS registration on current PLMN failed multiple times.
+ * The radio shall block the current PLMN or disable the RAT during EPS or 5GS mobility
+ * management timer value as per the carrier requirements.
+ * @hide
+ */
+ @SystemApi
+ public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT = 2;
+
/**@hide*/
// Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
// and WWAN are more accurate constants.
@@ -167,12 +203,12 @@ public interface RegistrationManager {
}
@Override
- public void onDeregistered(ImsReasonInfo info) {
+ public void onDeregistered(ImsReasonInfo info, @SuggestedAction int suggestedAction) {
if (mLocalCallback == null) return;
final long callingIdentity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> mLocalCallback.onUnregistered(info));
+ mExecutor.execute(() -> mLocalCallback.onUnregistered(info, suggestedAction));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -258,6 +294,21 @@ public interface RegistrationManager {
}
/**
+ * Notifies the framework when the IMS Provider is unregistered from the IMS network.
+ *
+ * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+ * @param suggestedAction the expected behavior of radio protocol stack.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void onUnregistered(@NonNull ImsReasonInfo info,
+ @SuggestedAction int suggestedAction) {
+ // Default impl to keep backwards compatibility with old implementations
+ onUnregistered(info);
+ }
+
+ /**
* A failure has occurred when trying to handover registration to another technology type.
*
* @param imsTransportType The transport type that has failed to handover registration to.
diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
index ea4480dc7958..cf7e9e168f67 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
@@ -64,6 +64,7 @@ interface IImsMmTelFeature {
void setSmsListener(IImsSmsListener l);
oneway void sendSms(in int token, int messageRef, String format, String smsc, boolean retry,
in byte[] pdu);
+ oneway void onMemoryAvailable(int token);
oneway void acknowledgeSms(int token, int messageRef, int result);
oneway void acknowledgeSmsWithPdu(int token, int messageRef, int result, in byte[] pdu);
oneway void acknowledgeSmsReport(int token, int messageRef, int result);
diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
index 52464703c608..640426b45ba3 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
@@ -34,4 +34,5 @@ interface IImsMmTelListener {
void onIncomingCall(IImsCallSession c, in Bundle extras);
void onRejectedCall(in ImsCallProfile callProfile, in ImsReasonInfo reason);
oneway void onVoiceMessageCountUpdate(int count);
+ oneway void onAudioModeIsVoipChanged(int imsAudioHandler);
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl
index 4fd904041365..219c9c88d825 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl
@@ -31,4 +31,5 @@ interface IImsRegistration {
oneway void triggerFullNetworkRegistration(int sipCode, String sipReason);
oneway void triggerUpdateSipDelegateRegistration();
oneway void triggerSipDelegateDeregistration();
+ oneway void triggerDeregistration(int reason);
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
index 179407c983e5..069eb469ef11 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
@@ -31,7 +31,7 @@ import android.telephony.ims.ImsRegistrationAttributes;
oneway interface IImsRegistrationCallback {
void onRegistered(in ImsRegistrationAttributes attr);
void onRegistering(in ImsRegistrationAttributes attr);
- void onDeregistered(in ImsReasonInfo info);
+ void onDeregistered(in ImsReasonInfo info, int suggestedAction);
void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info);
void onSubscriberAssociatedUriChanged(in Uri[] uris);
-} \ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 8184424fef26..4710c1f4dbf3 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -269,6 +269,12 @@ public class MmTelFeature extends ImsFeature {
}
@Override
+ public void onMemoryAvailable(int token) {
+ executeMethodAsyncNoException(() -> MmTelFeature.this
+ .onMemoryAvailable(token), "onMemoryAvailable");
+ }
+
+ @Override
public void acknowledgeSms(int token, int messageRef, int result) {
executeMethodAsyncNoException(() -> MmTelFeature.this
.acknowledgeSms(token, messageRef, result), "acknowledgeSms");
@@ -573,6 +579,17 @@ public class MmTelFeature extends ImsFeature {
public void onVoiceMessageCountUpdate(int count) {
}
+
+ /**
+ * Called to set the audio handler for this connection.
+ * @param imsAudioHandler an {@link ImsAudioHandler} used to handle the audio
+ * for this IMS call.
+ * @hide
+ */
+ @Override
+ public void onAudioModeIsVoipChanged(int imsAudioHandler) {
+
+ }
}
/**
@@ -622,6 +639,29 @@ public class MmTelFeature extends ImsFeature {
public static final String EXTRA_IS_UNKNOWN_CALL =
"android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
+ /** @hide */
+ @IntDef(flag = true,
+ value = {
+ AUDIO_HANDLER_ANDROID,
+ AUDIO_HANDLER_BASEBAND
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImsAudioHandler {}
+
+ /**
+ * Audio Handler - Android
+ * @hide
+ */
+ @SystemApi
+ public static final int AUDIO_HANDLER_ANDROID = 0;
+
+ /**
+ * Audio Handler - Baseband
+ * @hide
+ */
+ @SystemApi
+ public static final int AUDIO_HANDLER_BASEBAND = 1;
+
private IImsMmTelListener mListener;
/**
@@ -768,6 +808,28 @@ public class MmTelFeature extends ImsFeature {
}
/**
+ * Sets the audio handler for this connection. The vendor IMS stack will invoke this API
+ * to inform Telephony/Telecom layers about which audio handlers i.e. either Android or Modem
+ * shall be used for handling the IMS call audio.
+ *
+ * @param imsAudioHandler {@link MmTelFeature#ImsAudioHandler} used to handle the audio
+ * for this IMS call.
+ * @hide
+ */
+ @SystemApi
+ public final void setCallAudioHandler(@ImsAudioHandler int imsAudioHandler) {
+ IImsMmTelListener listener = getListener();
+ if (listener == null) {
+ throw new IllegalStateException("Session is not available.");
+ }
+ try {
+ listener.onAudioModeIsVoipChanged(imsAudioHandler);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* Provides the MmTelFeature with the ability to return the framework Capability Configuration
* for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and
* includes a capability A to enable or disable, this method should return the correct enabled
@@ -1089,6 +1151,10 @@ public class MmTelFeature extends ImsFeature {
getSmsImplementation().sendSms(token, messageRef, format, smsc, isRetry, pdu);
}
+ private void onMemoryAvailable(int token) {
+ getSmsImplementation().onMemoryAvailable(token);
+ }
+
private void acknowledgeSms(int token, int messageRef,
@ImsSmsImplBase.DeliverStatusResult int result) {
getSmsImplementation().acknowledgeSms(token, messageRef, result);
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 6fc1cc828a2c..117593aef3e5 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -64,7 +64,8 @@ public class ImsRegistrationImplBase {
REGISTRATION_TECH_LTE,
REGISTRATION_TECH_IWLAN,
REGISTRATION_TECH_CROSS_SIM,
- REGISTRATION_TECH_NR
+ REGISTRATION_TECH_NR,
+ REGISTRATION_TECH_3G
})
@Retention(RetentionPolicy.SOURCE)
public @interface ImsRegistrationTech {}
@@ -92,10 +93,15 @@ public class ImsRegistrationImplBase {
public static final int REGISTRATION_TECH_NR = 3;
/**
+ * This ImsService is registered to IMS via 3G.
+ */
+ public static final int REGISTRATION_TECH_3G = 4;
+
+ /**
* This is used to check the upper range of registration tech
* @hide
*/
- public static final int REGISTRATION_TECH_MAX = REGISTRATION_TECH_NR + 1;
+ public static final int REGISTRATION_TECH_MAX = REGISTRATION_TECH_3G + 1;
// Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current
// state.
@@ -104,6 +110,73 @@ public class ImsRegistrationImplBase {
// yet.
private static final int REGISTRATION_STATE_UNKNOWN = -1;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"REASON_"},
+ value = {
+ REASON_UNKNOWN,
+ REASON_SIM_REMOVED,
+ REASON_SIM_REFRESH,
+ REASON_ALLOWED_NETWORK_TYPES_CHANGED,
+ REASON_NON_IMS_CAPABLE_NETWORK,
+ REASON_RADIO_POWER_OFF,
+ REASON_HANDOVER_FAILED,
+ REASON_VOPS_NOT_SUPPORTED,
+ })
+ public @interface ImsDeregistrationReason{}
+
+ /**
+ * Unspecified reason.
+ * @hide
+ */
+ public static final int REASON_UNKNOWN = 0;
+
+ /**
+ * Since SIM is removed, the credentials for IMS service is also removed.
+ * @hide
+ */
+ public static final int REASON_SIM_REMOVED = 1;
+
+ /**
+ * Detach from the network shall be performed due to the SIM refresh. IMS service should be
+ * deregistered before that procedure.
+ * @hide
+ */
+ public static final int REASON_SIM_REFRESH = 2;
+
+ /**
+ * The allowed network types have changed, resulting in a network type
+ * that does not support IMS.
+ * @hide
+ */
+ public static final int REASON_ALLOWED_NETWORK_TYPES_CHANGED = 3;
+
+ /**
+ * The device camped on a network that does not support IMS.
+ * @hide
+ */
+ public static final int REASON_NON_IMS_CAPABLE_NETWORK = 4;
+
+ /**
+ * IMS service should be deregistered from the network before turning off the radio.
+ * @hide
+ */
+ public static final int REASON_RADIO_POWER_OFF = 5;
+
+ /**
+ * Since the handover is failed or not allowed, the data service for IMS shall be
+ * disconnected.
+ * @hide
+ */
+ public static final int REASON_HANDOVER_FAILED = 6;
+
+ /**
+ * The network is changed to a network that does not support voice over IMS.
+ * @hide
+ */
+ public static final int REASON_VOPS_NOT_SUPPORTED = 7;
+
private Executor mExecutor;
/**
@@ -182,6 +255,12 @@ public class ImsRegistrationImplBase {
.triggerSipDelegateDeregistration(), "triggerSipDelegateDeregistration");
}
+ @Override
+ public void triggerDeregistration(@ImsDeregistrationReason int reason) {
+ executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
+ .triggerDeregistration(reason), "triggerDeregistration");
+ }
+
// Call the methods with a clean calling identity on the executor and wait indefinitely for
// the future to return.
private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
@@ -228,6 +307,8 @@ public class ImsRegistrationImplBase {
private int mRegistrationState = REGISTRATION_STATE_UNKNOWN;
// Locked on mLock, create unspecified disconnect cause.
private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo();
+ // Locked on mLock
+ private int mLastDisconnectSuggestedAction = RegistrationManager.SUGGESTED_ACTION_NONE;
// We hold onto the uris each time they change so that we can send it to a callback when its
// first added.
@@ -303,6 +384,19 @@ public class ImsRegistrationImplBase {
// Stub implementation, ImsService should implement this
}
+ /**
+ * Requests IMS stack to perform graceful IMS deregistration before radio performing
+ * network detach in the events of SIM remove, refresh or and so on. The radio waits for
+ * the IMS deregistration, which will be notified by telephony via
+ * {@link android.hardware.radio.ims.IRadioIms#updateImsRegistrationInfo()},
+ * or a certain timeout interval to start the network detach procedure.
+ *
+ * @param reason the reason why the deregistration is triggered.
+ * @hide
+ */
+ public void triggerDeregistration(@ImsDeregistrationReason int reason) {
+ // Stub Implementation, can be overridden by ImsService
+ }
/**
* Notify the framework that the device is connected to the IMS network.
@@ -381,12 +475,37 @@ public class ImsRegistrationImplBase {
*/
@SystemApi
public final void onDeregistered(ImsReasonInfo info) {
- updateToDisconnectedState(info);
+ // Default impl to keep backwards compatibility with old implementations
+ onDeregistered(info, RegistrationManager.SUGGESTED_ACTION_NONE);
+ }
+
+ /**
+ * Notify the framework that the device is disconnected from the IMS network.
+ * <p>
+ * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo,int)}, you should ensure that any
+ * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent
+ * to the framework. For example,
+ * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}
+ * and
+ * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}
+ * may be set to unavailable to ensure the framework knows these services are no longer
+ * available due to de-registration. If you do not report capability changes impacted by
+ * de-registration, the framework will not know which features are no longer available as a
+ * result.
+ *
+ * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+ * @param suggestedAction the expected behavior of radio protocol stack.
+ * @hide This API is not part of the Android public SDK API
+ */
+ @SystemApi
+ public final void onDeregistered(@Nullable ImsReasonInfo info,
+ @RegistrationManager.SuggestedAction int suggestedAction) {
+ updateToDisconnectedState(info, suggestedAction);
// ImsReasonInfo should never be null.
final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo();
mCallbacks.broadcastAction((c) -> {
try {
- c.onDeregistered(reasonInfo);
+ c.onDeregistered(reasonInfo, suggestedAction);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback.");
}
@@ -445,10 +564,12 @@ public class ImsRegistrationImplBase {
mRegistrationAttributes = attributes;
mRegistrationState = newState;
mLastDisconnectCause = null;
+ mLastDisconnectSuggestedAction = RegistrationManager.SUGGESTED_ACTION_NONE;
}
}
- private void updateToDisconnectedState(ImsReasonInfo info) {
+ private void updateToDisconnectedState(ImsReasonInfo info,
+ @RegistrationManager.SuggestedAction int suggestedAction) {
synchronized (mLock) {
//We don't want to send this info over if we are disconnected
mUrisSet = false;
@@ -458,6 +579,7 @@ public class ImsRegistrationImplBase {
RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
if (info != null) {
mLastDisconnectCause = info;
+ mLastDisconnectSuggestedAction = suggestedAction;
} else {
Log.w(LOG_TAG, "updateToDisconnectedState: no ImsReasonInfo provided.");
mLastDisconnectCause = new ImsReasonInfo();
@@ -474,18 +596,20 @@ public class ImsRegistrationImplBase {
int state;
ImsRegistrationAttributes attributes;
ImsReasonInfo disconnectInfo;
+ int suggestedAction;
boolean urisSet;
Uri[] uris;
synchronized (mLock) {
state = mRegistrationState;
attributes = mRegistrationAttributes;
disconnectInfo = mLastDisconnectCause;
+ suggestedAction = mLastDisconnectSuggestedAction;
urisSet = mUrisSet;
uris = mUris;
}
switch (state) {
case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: {
- c.onDeregistered(disconnectInfo);
+ c.onDeregistered(disconnectInfo, suggestedAction);
break;
}
case RegistrationManager.REGISTRATION_STATE_REGISTERING: {
diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
index 66833d18a945..daab84eb077c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
@@ -171,6 +171,20 @@ public class ImsSmsImplBase {
}
/**
+ * This method will be triggered by the platform when memory becomes available to receive SMS
+ * after a memory full event. This method should be implemented by IMS providers to
+ * send RP-SMMA notification from SMS Relay Layer to server over IMS as per section 7.3.2 of
+ * TS 124.11. Once the RP-SMMA Notification is sent to the network. The network will deliver all
+ * the pending messages which failed due to Unavailability of Memory.
+ *
+ * @param token unique token generated in {@link ImsSmsDispatcher#onMemoryAvailable(void)} that
+ * should be used when triggering callbacks for this specific message.
+ */
+ public void onMemoryAvailable(int token) {
+ // Base Implementation - Should be overridden
+ }
+
+ /**
* This method will be triggered by the platform after
* {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS
* provider.
diff --git a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
index 89620eaaf609..1788bda62302 100644
--- a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
+++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
@@ -38,4 +38,6 @@ interface ICarrierConfigLoader {
String getDefaultCarrierServicePackageName();
+ PersistableBundle getConfigSubsetForSubIdWithFeature(int subId, String callingPackage,
+ String callingFeatureId, in String[] carrierConfigs);
}
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 9ec3c6716a29..0e23f364134c 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -530,6 +530,25 @@ interface ISms {
int subId, String callingPkg, String prefixes, in PendingIntent intent);
/**
+ * set Memory Status in SmsStorageMonitor
+ *
+ * @param subId the subscription Id.
+ * @param callingPackage the package name of the calling app.
+ * @param isStorageAvailable sets StorageAvailable to false or true
+ * for testing behaviour of SmsStorageMonitor
+ */
+ void setStorageMonitorMemoryStatusOverride(int subId, boolean isStorageAvailable);
+
+ /**
+ * reset Memory Status change made by TestApi setStorageMonitorMemoryStatusOverride
+ * in SmsStorageMonitor
+ *
+ * @param subId the subscription Id.
+ * @param callingPackage the package name of the calling app.
+ */
+ void clearStorageMonitorMemoryStatusOverride(int subId);
+
+ /**
* Check if the destination is a possible premium short code.
*
* @param destAddress the destination address to test for possible short code
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index c361d5bec097..686455688203 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -192,6 +192,16 @@ public class ISmsImplBase extends ISms.Stub {
}
@Override
+ public void setStorageMonitorMemoryStatusOverride(int subId, boolean storageAvailable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clearStorageMonitorMemoryStatusOverride(int subId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public int checkSmsShortCodeDestination(int subid, String callingPackage,
String callingFeatureId, String destAddress, String countryIso) {
throw new UnsupportedOperationException();
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index e9cea6843a82..280d25950228 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -274,11 +274,6 @@ interface ISub {
boolean isSubscriptionEnabled(int subId);
int getEnabledSubscriptionId(int slotIndex);
- /**
- * Get the SIM state for the slot index
- * @return SIM state as the ordinal of IccCardConstants.State
- */
- int getSimStateForSlotIndex(int slotIndex);
boolean isActiveSubId(int subId, String callingPackage, String callingFeatureId);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 616ea50e4185..9445d0763c98 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2628,5 +2628,34 @@ interface ITelephony {
* {@code null} if the functionality is not supported.
* @hide
*/
- ComponentName getDefaultRespondViaMessageApplication(int subId, boolean updateIfNeeded);
+ ComponentName getDefaultRespondViaMessageApplication(int subId, boolean updateIfNeeded);
+
+ /**
+ * Get the SIM state for the logical SIM slot index.
+ *
+ * @param slotIndex Logical SIM slot index.
+ */
+ int getSimStateForSlotIndex(int slotIndex);
+
+ /**
+ * Set whether the radio is able to connect with null ciphering or integrity
+ * algorithms. This is a global setting and will apply to all active subscriptions
+ * and all new subscriptions after this.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @param enabled when true, null cipher and integrity algorithms are allowed.
+ * @hide
+ */
+ void setNullCipherAndIntegrityEnabled(boolean enabled);
+
+ /**
+ * Get whether the radio is able to connect with null ciphering or integrity
+ * algorithms. Note that this retrieves the phone-global preference and not
+ * the state of the radio.
+ *
+ * @hide
+ */
+ boolean isNullCipherAndIntegrityPreferenceEnabled();
}
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
index 7ac51b7e3342..b313c9fc6c28 100644
--- a/tests/vcn/java/android/net/vcn/VcnConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -16,7 +16,12 @@
package android.net.vcn;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -24,6 +29,7 @@ import static org.mockito.Mockito.mock;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Parcel;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -42,19 +48,36 @@ public class VcnConfigTest {
private static final Set<VcnGatewayConnectionConfig> GATEWAY_CONNECTION_CONFIGS =
Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig());
+ private static final Set<Integer> RESTRICTED_TRANSPORTS = new ArraySet<>();
+
+ static {
+ RESTRICTED_TRANSPORTS.add(TRANSPORT_WIFI);
+ RESTRICTED_TRANSPORTS.add(TRANSPORT_CELLULAR);
+ }
+
private final Context mContext = mock(Context.class);
// Public visibility for VcnManagementServiceTest
- public static VcnConfig buildTestConfig(@NonNull Context context) {
+ public static VcnConfig buildTestConfig(
+ @NonNull Context context, Set<Integer> restrictedTransports) {
VcnConfig.Builder builder = new VcnConfig.Builder(context);
for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) {
builder.addGatewayConnectionConfig(gatewayConnectionConfig);
}
+ if (restrictedTransports != null) {
+ builder.setRestrictedUnderlyingNetworkTransports(restrictedTransports);
+ }
+
return builder.build();
}
+ // Public visibility for VcnManagementServiceTest
+ public static VcnConfig buildTestConfig(@NonNull Context context) {
+ return buildTestConfig(context, null);
+ }
+
@Before
public void setUp() throws Exception {
doReturn(TEST_PACKAGE_NAME).when(mContext).getOpPackageName();
@@ -91,11 +114,25 @@ public class VcnConfigTest {
}
@Test
- public void testBuilderAndGetters() {
+ public void testBuilderAndGettersDefaultValues() {
final VcnConfig config = buildTestConfig(mContext);
assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName());
assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs());
+ assertFalse(config.isTestModeProfile());
+ assertEquals(
+ Collections.singleton(TRANSPORT_WIFI),
+ config.getRestrictedUnderlyingNetworkTransports());
+ }
+
+ @Test
+ public void testBuilderAndGettersConfigRestrictedTransports() {
+ final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);
+
+ assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName());
+ assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs());
+ assertFalse(config.isTestModeProfile());
+ assertEquals(RESTRICTED_TRANSPORTS, config.getRestrictedUnderlyingNetworkTransports());
}
@Test
@@ -106,6 +143,24 @@ public class VcnConfigTest {
}
@Test
+ public void testPersistableBundleWithRestrictedTransports() {
+ final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);
+
+ assertEquals(config, new VcnConfig(config.toPersistableBundle()));
+ }
+
+ @Test
+ public void testEqualityWithRestrictedTransports() {
+ final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);
+ final VcnConfig configEqual = buildTestConfig(mContext, RESTRICTED_TRANSPORTS);
+ final VcnConfig configNotEqual =
+ buildTestConfig(mContext, Collections.singleton(TRANSPORT_WIFI));
+
+ assertEquals(config, configEqual);
+ assertNotEquals(config, configNotEqual);
+ }
+
+ @Test
public void testParceling() {
final VcnConfig config = buildTestConfig(mContext);
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 258642ac229e..075bc5e5214e 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -258,7 +258,7 @@ public class VcnManagementServiceTest {
doReturn(Collections.singleton(TRANSPORT_WIFI))
.when(mMockDeps)
- .getRestrictedTransports(any(), any());
+ .getRestrictedTransports(any(), any(), any());
}
@@ -1038,18 +1038,18 @@ public class VcnManagementServiceTest {
new LinkProperties());
}
- private void checkGetRestrictedTransports(
+ private void checkGetRestrictedTransportsFromCarrierConfig(
ParcelUuid subGrp,
TelephonySubscriptionSnapshot lastSnapshot,
Set<Integer> expectedTransports) {
Set<Integer> result =
new VcnManagementService.Dependencies()
- .getRestrictedTransports(subGrp, lastSnapshot);
+ .getRestrictedTransportsFromCarrierConfig(subGrp, lastSnapshot);
assertEquals(expectedTransports, result);
}
@Test
- public void testGetRestrictedTransports() {
+ public void testGetRestrictedTransportsFromCarrierConfig() {
final Set<Integer> restrictedTransports = new ArraySet<>();
restrictedTransports.add(TRANSPORT_CELLULAR);
restrictedTransports.add(TRANSPORT_WIFI);
@@ -1065,11 +1065,12 @@ public class VcnManagementServiceTest {
mock(TelephonySubscriptionSnapshot.class);
doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
- checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ checkGetRestrictedTransportsFromCarrierConfig(
+ TEST_UUID_2, lastSnapshot, restrictedTransports);
}
@Test
- public void testGetRestrictedTransports_noRestrictPolicyConfigured() {
+ public void testGetRestrictedTransportsFromCarrierConfig_noRestrictPolicyConfigured() {
final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
final PersistableBundleWrapper carrierConfig =
@@ -1078,17 +1079,54 @@ public class VcnManagementServiceTest {
mock(TelephonySubscriptionSnapshot.class);
doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
- checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ checkGetRestrictedTransportsFromCarrierConfig(
+ TEST_UUID_2, lastSnapshot, restrictedTransports);
}
@Test
- public void testGetRestrictedTransports_noCarrierConfig() {
+ public void testGetRestrictedTransportsFromCarrierConfig_noCarrierConfig() {
final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
final TelephonySubscriptionSnapshot lastSnapshot =
mock(TelephonySubscriptionSnapshot.class);
- checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ checkGetRestrictedTransportsFromCarrierConfig(
+ TEST_UUID_2, lastSnapshot, restrictedTransports);
+ }
+
+ @Test
+ public void testGetRestrictedTransportsFromCarrierConfigAndVcnConfig() {
+ // Configure restricted transport in CarrierConfig
+ final Set<Integer> restrictedTransportInCarrierConfig =
+ Collections.singleton(TRANSPORT_WIFI);
+
+ PersistableBundle carrierConfigBundle = new PersistableBundle();
+ carrierConfigBundle.putIntArray(
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ restrictedTransportInCarrierConfig.stream().mapToInt(i -> i).toArray());
+ final PersistableBundleWrapper carrierConfig =
+ new PersistableBundleWrapper(carrierConfigBundle);
+
+ final TelephonySubscriptionSnapshot lastSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+ // Configure restricted transport in VcnConfig
+ final Context mockContext = mock(Context.class);
+ doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName();
+ final VcnConfig vcnConfig =
+ VcnConfigTest.buildTestConfig(
+ mockContext, Collections.singleton(TRANSPORT_CELLULAR));
+
+ // Verifications
+ final Set<Integer> expectedTransports = new ArraySet<>();
+ expectedTransports.add(TRANSPORT_CELLULAR);
+ expectedTransports.add(TRANSPORT_WIFI);
+
+ Set<Integer> result =
+ new VcnManagementService.Dependencies()
+ .getRestrictedTransports(TEST_UUID_2, lastSnapshot, vcnConfig);
+ assertEquals(expectedTransports, result);
}
private void checkGetUnderlyingNetworkPolicy(
@@ -1103,7 +1141,7 @@ public class VcnManagementServiceTest {
if (isTransportRestricted) {
restrictedTransports.add(transportType);
}
- doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any());
+ doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any(), any());
final VcnUnderlyingNetworkPolicy policy =
startVcnAndGetPolicyForTransport(
@@ -1201,7 +1239,7 @@ public class VcnManagementServiceTest {
public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception {
doReturn(Collections.singleton(TRANSPORT_WIFI))
.when(mMockDeps)
- .getRestrictedTransports(any(), any());
+ .getRestrictedTransports(any(), any(), any());
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */);
@@ -1344,6 +1382,23 @@ public class VcnManagementServiceTest {
}
@Test
+ public void testVcnConfigChangeUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ final Context mockContext = mock(Context.class);
+ doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName();
+ final VcnConfig vcnConfig =
+ VcnConfigTest.buildTestConfig(
+ mockContext, Collections.singleton(TRANSPORT_CELLULAR));
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME);
+
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ @Test
public void testRemoveVcnUpdatesPolicyListener() throws Exception {
setupActiveSubscription(TEST_UUID_2);
@@ -1375,7 +1430,7 @@ public class VcnManagementServiceTest {
setupActiveSubscription(TEST_UUID_2);
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
- mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListenerForTest(mMockPolicyListener);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
final TelephonySubscriptionSnapshot snapshot =
buildSubscriptionSnapshot(
diff --git a/tools/aapt2/ApkInfo.proto b/tools/aapt2/ApkInfo.proto
index 80bdccbc4dd2..b5ff71fa5935 100644
--- a/tools/aapt2/ApkInfo.proto
+++ b/tools/aapt2/ApkInfo.proto
@@ -40,7 +40,8 @@ message Badging {
PackageInfo package = 1;
Application application = 2;
UsesSdk uses_sdk = 3;
- UsesConfiguration uses_configuration = 4;
+ // Previously: UsesConfiguration uses_configuration = 4;
+ reserved 4;
SupportsScreen supports_screen = 5;
SupportsInput supports_input = 6;
LaunchableActivity launchable_activity = 7;
@@ -57,6 +58,8 @@ message Badging {
repeated string locales = 17;
repeated int32 densities = 18;
+ repeated UsesPackage uses_packages = 51;
+ repeated UsesConfiguration uses_configurations = 52;
repeated FeatureGroup feature_groups = 53;
repeated UsesPermission uses_permissions = 54;
repeated Permission permissions = 55;
@@ -64,7 +67,6 @@ message Badging {
repeated UsesStaticLibrary uses_static_libraries = 57;
repeated UsesSdkLibrary uses_sdk_libraries = 58;
repeated UsesNativeLibrary uses_native_libraries = 59;
- repeated UsesPackage uses_packages = 51;
repeated Metadata metadata = 62;
repeated Property properties = 63;
diff --git a/tools/aapt2/cmd/Dump_test.cpp b/tools/aapt2/cmd/Dump_test.cpp
index b1c69cd9a7b7..df35ebbc064d 100644
--- a/tools/aapt2/cmd/Dump_test.cpp
+++ b/tools/aapt2/cmd/Dump_test.cpp
@@ -108,4 +108,21 @@ TEST_F(DumpTest, DumpBadgingPermissionsOnly) {
ASSERT_EQ(output, expected);
}
+TEST_F(DumpTest, DumpBadgingApkBuiltWithAaptAndTagsInWrongPlace) {
+ auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests",
+ "DumpTest", "built_with_aapt.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output, /* include_meta_data= */ false,
+ /* only_permissions= */ false);
+
+ std::string expected;
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "built_with_aapt_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index d60869af2846..d1957fb30cb9 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -223,7 +223,8 @@ class ManifestExtractor {
Element() = default;
virtual ~Element() = default;
- static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
+ static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el,
+ const std::string& parent_tag);
/** Writes out the extracted contents of the element. */
virtual void Print(text::Printer* printer) {
@@ -249,10 +250,15 @@ class ManifestExtractor {
}
/** Retrieves the extracted xml element tag. */
- const std::string tag() const {
+ const std::string& tag() const {
return tag_;
}
+ /** Whether this element has special Extract/Print/ToProto logic. */
+ bool is_featured() const {
+ return featured_;
+ }
+
protected:
ManifestExtractor* extractor() const {
return extractor_;
@@ -394,6 +400,8 @@ class ManifestExtractor {
return &(*intValue->value);
} else if (RawString* rawValue = ValueCast<RawString>(value)) {
return &(*rawValue->value);
+ } else if (StyledString* styledStrValue = ValueCast<StyledString>(value)) {
+ return &(styledStrValue->value->value);
} else if (FileReference* strValue = ValueCast<FileReference>(value)) {
return &(*strValue->path);
}
@@ -424,6 +432,7 @@ class ManifestExtractor {
ManifestExtractor* extractor_;
std::vector<std::unique_ptr<Element>> children_;
std::string tag_;
+ bool featured_ = false;
};
friend Element;
@@ -446,7 +455,7 @@ class ManifestExtractor {
bool DumpProto(pb::Badging* out_badging);
/** Recursively visit the xml element tree and return a processed badging element tree. */
- std::unique_ptr<Element> Visit(xml::Element* element);
+ std::unique_ptr<Element> Visit(xml::Element* element, const std::string& parent_tag);
/** Resets target SDK to 0. */
void ResetTargetSdk() {
@@ -485,7 +494,7 @@ class ManifestExtractor {
}
/** Retrieves the current stack of parent during data extraction. */
- const std::vector<Element*> parent_stack() const {
+ const std::vector<Element*>& parent_stack() const {
return parent_stack_;
}
@@ -533,8 +542,9 @@ static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
if (f(root)) {
return root;
}
- for (auto& child : root->children()) {
- if (auto b2 = FindElement(child.get(), f)) {
+ const auto& children = root->children();
+ for (auto it = children.rbegin(); it != children.rend(); ++it) {
+ if (auto b2 = FindElement(it->get(), f)) {
return b2;
}
}
@@ -901,7 +911,7 @@ class UsesConfiguarion : public ManifestExtractor::Element {
}
void ToProto(pb::Badging* out_badging) override {
- auto out_configuration = out_badging->mutable_uses_configuration();
+ auto out_configuration = out_badging->add_uses_configurations();
out_configuration->set_req_touch_screen(req_touch_screen);
out_configuration->set_req_keyboard_type(req_keyboard_type);
out_configuration->set_req_hard_keyboard(req_hard_keyboard);
@@ -1348,11 +1358,6 @@ class UsesPermission : public ManifestExtractor::Element {
std::string impliedReason;
void Extract(xml::Element* element) override {
- const auto parent_stack = extractor()->parent_stack();
- if (!extractor()->options_.only_permissions &&
- (parent_stack.size() != 1 || !ElementCast<Manifest>(parent_stack[0]))) {
- return;
- }
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
std::string feature =
GetAttributeStringDefault(FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
@@ -1477,11 +1482,6 @@ class UsesPermissionSdk23 : public ManifestExtractor::Element {
const int32_t* maxSdkVersion = nullptr;
void Extract(xml::Element* element) override {
- const auto parent_stack = extractor()->parent_stack();
- if (!extractor()->options_.only_permissions &&
- (parent_stack.size() != 1 || !ElementCast<Manifest>(parent_stack[0]))) {
- return;
- }
name = GetAttributeString(FindAttribute(element, NAME_ATTR));
maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
@@ -1717,11 +1717,8 @@ class UsesLibrary : public ManifestExtractor::Element {
int required;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
}
void Print(text::Printer* printer) override {
@@ -1749,12 +1746,9 @@ class StaticLibrary : public ManifestExtractor::Element {
int versionMajor;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
}
void Print(text::Printer* printer) override {
@@ -1781,13 +1775,10 @@ class UsesStaticLibrary : public ManifestExtractor::Element {
std::vector<std::string> certDigests;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- AddCertDigest(element);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
}
void AddCertDigest(xml::Element* element) {
@@ -1829,11 +1820,8 @@ class SdkLibrary : public ManifestExtractor::Element {
int versionMajor;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
}
void Print(text::Printer* printer) override {
@@ -1857,12 +1845,9 @@ class UsesSdkLibrary : public ManifestExtractor::Element {
std::vector<std::string> certDigests;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- AddCertDigest(element);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
}
void AddCertDigest(xml::Element* element) {
@@ -1902,11 +1887,8 @@ class UsesNativeLibrary : public ManifestExtractor::Element {
int required;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
}
void Print(text::Printer* printer) override {
@@ -2251,14 +2233,11 @@ class UsesPackage : public ManifestExtractor::Element {
std::vector<std::string> certDigests;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
- name = GetAttributeString(FindAttribute(element, NAME_ATTR));
- version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- AddCertDigest(element);
- }
+ packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
}
void AddCertDigest(xml::Element* element) {
@@ -2480,7 +2459,7 @@ bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
// Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
// printing only permission elements is requested
if (options_.only_permissions) {
- root_element_ = ManifestExtractor::Element::Inflate(this, element);
+ root_element_ = ManifestExtractor::Element::Inflate(this, element, "");
if (auto manifest = ElementCast<Manifest>(root_element_.get())) {
manifest->only_package_name = true;
@@ -2489,7 +2468,7 @@ bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
|| child->name == "permission") {
// Inflate the element and its descendants
- auto permission_element = Visit(child);
+ auto permission_element = Visit(child, "manifest");
manifest->AddChild(permission_element);
}
}
@@ -2528,7 +2507,7 @@ bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
}
// Extract badging information
- root_element_ = Visit(element);
+ root_element_ = Visit(element, "");
// Filter out all "uses-sdk" tags besides the very last tag. The android runtime only uses the
// attribute values from the last defined tag.
@@ -2683,7 +2662,7 @@ bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
(meta_data->name == "android.nfc.cardemulation.off_host_apdu_service" &&
offhost_apdu_action)) {
// Attempt to load the resource file
- if (!meta_data->resource.empty()) {
+ if (meta_data->resource.empty()) {
return;
}
auto resource = this->apk_->LoadXml(meta_data->resource, diag);
@@ -2878,58 +2857,66 @@ bool ManifestExtractor::DumpProto(pb::Badging* out_badging) {
return true;
}
+template <typename T>
+constexpr const char* GetExpectedTagForType() {
+ // This array does not appear at runtime, as GetExpectedTagForType function is used by compiler
+ // to inject proper 'expected_tag' into ElementCast.
+ std::array<std::pair<const char*, bool>, 37> tags = {
+ std::make_pair("action", std::is_same<Action, T>::value),
+ std::make_pair("activity", std::is_same<Activity, T>::value),
+ std::make_pair("additional-certificate", std::is_same<AdditionalCertificate, T>::value),
+ std::make_pair("application", std::is_same<Application, T>::value),
+ std::make_pair("category", std::is_same<Category, T>::value),
+ std::make_pair("compatible-screens", std::is_same<CompatibleScreens, T>::value),
+ std::make_pair("feature-group", std::is_same<FeatureGroup, T>::value),
+ std::make_pair("input-type", std::is_same<InputType, T>::value),
+ std::make_pair("intent-filter", std::is_same<IntentFilter, T>::value),
+ std::make_pair("meta-data", std::is_same<MetaData, T>::value),
+ std::make_pair("manifest", std::is_same<Manifest, T>::value),
+ std::make_pair("original-package", std::is_same<OriginalPackage, T>::value),
+ std::make_pair("overlay", std::is_same<Overlay, T>::value),
+ std::make_pair("package-verifier", std::is_same<PackageVerifier, T>::value),
+ std::make_pair("permission", std::is_same<Permission, T>::value),
+ std::make_pair("property", std::is_same<Property, T>::value),
+ std::make_pair("provider", std::is_same<Provider, T>::value),
+ std::make_pair("receiver", std::is_same<Receiver, T>::value),
+ std::make_pair("required-feature", std::is_same<RequiredFeature, T>::value),
+ std::make_pair("required-not-feature", std::is_same<RequiredNotFeature, T>::value),
+ std::make_pair("screen", std::is_same<Screen, T>::value),
+ std::make_pair("service", std::is_same<Service, T>::value),
+ std::make_pair("sdk-library", std::is_same<SdkLibrary, T>::value),
+ std::make_pair("static-library", std::is_same<StaticLibrary, T>::value),
+ std::make_pair("supports-gl-texture", std::is_same<SupportsGlTexture, T>::value),
+ std::make_pair("supports-input", std::is_same<SupportsInput, T>::value),
+ std::make_pair("supports-screens", std::is_same<SupportsScreen, T>::value),
+ std::make_pair("uses-configuration", std::is_same<UsesConfiguarion, T>::value),
+ std::make_pair("uses-feature", std::is_same<UsesFeature, T>::value),
+ std::make_pair("uses-library", std::is_same<UsesLibrary, T>::value),
+ std::make_pair("uses-native-library", std::is_same<UsesNativeLibrary, T>::value),
+ std::make_pair("uses-package", std::is_same<UsesPackage, T>::value),
+ std::make_pair("uses-permission", std::is_same<UsesPermission, T>::value),
+ std::make_pair("uses-permission-sdk-23", std::is_same<UsesPermissionSdk23, T>::value),
+ std::make_pair("uses-sdk", std::is_same<UsesSdkBadging, T>::value),
+ std::make_pair("uses-sdk-library", std::is_same<UsesSdkLibrary, T>::value),
+ std::make_pair("uses-static-library", std::is_same<UsesStaticLibrary, T>::value),
+ };
+ for (const auto& pair : tags) {
+ if (pair.second) {
+ return pair.first;
+ }
+ }
+ return nullptr;
+}
+
/**
* Returns the element casted to the type if the element is of that type. Otherwise, returns a null
* pointer.
**/
template<typename T>
T* ElementCast(ManifestExtractor::Element* element) {
- if (element == nullptr) {
- return nullptr;
- }
-
- const std::unordered_map<std::string, bool> kTagCheck = {
- {"action", std::is_base_of<Action, T>::value},
- {"activity", std::is_base_of<Activity, T>::value},
- {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
- {"application", std::is_base_of<Application, T>::value},
- {"category", std::is_base_of<Category, T>::value},
- {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
- {"feature-group", std::is_base_of<FeatureGroup, T>::value},
- {"input-type", std::is_base_of<InputType, T>::value},
- {"intent-filter", std::is_base_of<IntentFilter, T>::value},
- {"meta-data", std::is_base_of<MetaData, T>::value},
- {"manifest", std::is_base_of<Manifest, T>::value},
- {"original-package", std::is_base_of<OriginalPackage, T>::value},
- {"overlay", std::is_base_of<Overlay, T>::value},
- {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
- {"permission", std::is_base_of<Permission, T>::value},
- {"property", std::is_base_of<Property, T>::value},
- {"provider", std::is_base_of<Provider, T>::value},
- {"receiver", std::is_base_of<Receiver, T>::value},
- {"required-feature", std::is_base_of<RequiredFeature, T>::value},
- {"required-not-feature", std::is_base_of<RequiredNotFeature, T>::value},
- {"screen", std::is_base_of<Screen, T>::value},
- {"service", std::is_base_of<Service, T>::value},
- {"sdk-library", std::is_base_of<SdkLibrary, T>::value},
- {"static-library", std::is_base_of<StaticLibrary, T>::value},
- {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
- {"supports-input", std::is_base_of<SupportsInput, T>::value},
- {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
- {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
- {"uses-feature", std::is_base_of<UsesFeature, T>::value},
- {"uses-library", std::is_base_of<UsesLibrary, T>::value},
- {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
- {"uses-package", std::is_base_of<UsesPackage, T>::value},
- {"uses-permission", std::is_base_of<UsesPermission, T>::value},
- {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
- {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
- {"uses-sdk-library", std::is_base_of<UsesSdkLibrary, T>::value},
- {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
- };
-
- auto check = kTagCheck.find(element->tag());
- if (check != kTagCheck.end() && check->second) {
+ constexpr const char* expected_tag = GetExpectedTagForType<T>();
+ if (element != nullptr && expected_tag != nullptr && element->is_featured() &&
+ element->tag() == expected_tag) {
return static_cast<T*>(element);
}
return nullptr;
@@ -2941,9 +2928,9 @@ std::unique_ptr<T> CreateType() {
}
std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
- ManifestExtractor* extractor, xml::Element* el) {
- const std::unordered_map<std::string,
- std::function<std::unique_ptr<ManifestExtractor::Element>()>>
+ ManifestExtractor* extractor, xml::Element* el, const std::string& parent_tag) {
+ static const std::unordered_map<std::string_view,
+ std::function<std::unique_ptr<ManifestExtractor::Element>()>>
kTagCheck = {
{"action", &CreateType<Action>},
{"activity", &CreateType<Activity>},
@@ -2983,12 +2970,71 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
{"uses-sdk-library", &CreateType<UsesSdkLibrary>},
{"uses-static-library", &CreateType<UsesStaticLibrary>},
};
-
+ static constexpr std::array<std::pair<std::string_view, std::string_view>, 53>
+ kValidChildParentTags = {
+ std::make_pair("action", "intent-filter"),
+ std::make_pair("activity", "application"),
+ std::make_pair("additional-certificate", "uses-package"),
+ std::make_pair("additional-certificate", "uses-static-library"),
+ std::make_pair("application", "manifest"),
+ std::make_pair("category", "intent-filter"),
+ std::make_pair("compatible-screens", "manifest"),
+ std::make_pair("feature-group", "manifest"),
+ std::make_pair("input-type", "supports-input"),
+ std::make_pair("intent-filter", "activity"),
+ std::make_pair("intent-filter", "activity-alias"),
+ std::make_pair("intent-filter", "service"),
+ std::make_pair("intent-filter", "receiver"),
+ std::make_pair("intent-filter", "provider"),
+ std::make_pair("manifest", ""),
+ std::make_pair("meta-data", "activity"),
+ std::make_pair("meta-data", "activity-alias"),
+ std::make_pair("meta-data", "application"),
+ std::make_pair("meta-data", "service"),
+ std::make_pair("meta-data", "receiver"),
+ std::make_pair("meta-data", "provider"),
+ std::make_pair("original-package", "manifest"),
+ std::make_pair("overlay", "manifest"),
+ std::make_pair("package-verifier", "manifest"),
+ std::make_pair("permission", "manifest"),
+ std::make_pair("property", "activity"),
+ std::make_pair("property", "activity-alias"),
+ std::make_pair("property", "application"),
+ std::make_pair("property", "service"),
+ std::make_pair("property", "receiver"),
+ std::make_pair("property", "provider"),
+ std::make_pair("provider", "application"),
+ std::make_pair("receiver", "application"),
+ std::make_pair("required-feature", "uses-permission"),
+ std::make_pair("required-not-feature", "uses-permission"),
+ std::make_pair("screen", "compatible-screens"),
+ std::make_pair("service", "application"),
+ std::make_pair("sdk-library", "application"),
+ std::make_pair("static-library", "application"),
+ std::make_pair("supports-gl-texture", "manifest"),
+ std::make_pair("supports-input", "manifest"),
+ std::make_pair("supports-screens", "manifest"),
+ std::make_pair("uses-configuration", "manifest"),
+ std::make_pair("uses-feature", "feature-group"),
+ std::make_pair("uses-feature", "manifest"),
+ std::make_pair("uses-library", "application"),
+ std::make_pair("uses-native-library", "application"),
+ std::make_pair("uses-package", "application"),
+ std::make_pair("uses-permission", "manifest"),
+ std::make_pair("uses-permission-sdk-23", "manifest"),
+ std::make_pair("uses-sdk", "manifest"),
+ std::make_pair("uses-sdk-library", "application"),
+ std::make_pair("uses-static-library", "application"),
+ };
+ bool is_valid_tag = std::find(kValidChildParentTags.begin(), kValidChildParentTags.end(),
+ std::make_pair<std::string_view, std::string_view>(
+ el->name, parent_tag)) != kValidChildParentTags.end();
// Attempt to map the xml tag to a element inflater
std::unique_ptr<ManifestExtractor::Element> element;
auto check = kTagCheck.find(el->name);
- if (check != kTagCheck.end()) {
+ if (check != kTagCheck.end() && is_valid_tag) {
element = check->second();
+ element->featured_ = true;
} else {
element = util::make_unique<ManifestExtractor::Element>();
}
@@ -2999,13 +3045,14 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
return element;
}
-std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
- auto element = ManifestExtractor::Element::Inflate(this, el);
+std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(
+ xml::Element* el, const std::string& parent_tag) {
+ auto element = ManifestExtractor::Element::Inflate(this, el, parent_tag);
parent_stack_.insert(parent_stack_.begin(), element.get());
// Process the element and recursively visit the children
for (xml::Element* child : el->GetChildElements()) {
- auto v = Visit(child);
+ auto v = Visit(child, el->name);
element->AddChild(v);
}
diff --git a/tools/aapt2/integration-tests/DumpTest/built_with_aapt.apk b/tools/aapt2/integration-tests/DumpTest/built_with_aapt.apk
new file mode 100644
index 000000000000..090ebe5687dd
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/built_with_aapt.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt b/tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt
new file mode 100644
index 000000000000..cc0b3bf5d2fb
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt
@@ -0,0 +1,11 @@
+package: name='com.aapt.app' versionCode='222' versionName='222' platformBuildVersionName='12' platformBuildVersionCode='32' compileSdkVersion='32' compileSdkVersionCodename='12'
+sdkVersion:'22'
+targetSdkVersion:'32'
+application: label='App' icon=''
+feature-group: label=''
+ uses-feature: name='android.hardware.faketouch'
+ uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+supports-screens: 'small' 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+locales:
+densities:
diff --git a/tools/aapt2/integration-tests/DumpTest/components_expected.txt b/tools/aapt2/integration-tests/DumpTest/components_expected.txt
index 79b6706e4a9f..9c81fb83ca15 100644
--- a/tools/aapt2/integration-tests/DumpTest/components_expected.txt
+++ b/tools/aapt2/integration-tests/DumpTest/components_expected.txt
@@ -36,6 +36,7 @@ provides-component:'ime'
provides-component:'wallpaper'
provides-component:'accessibility'
provides-component:'print-service'
+provides-component:'payment'
provides-component:'search'
provides-component:'document-provider'
provides-component:'notification-listener'
diff --git a/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
index 4aed4afa2753..d866479f04db 100644
--- a/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
+++ b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
@@ -40,13 +40,6 @@ badging {
min_sdk_version: 21
target_sdk_version: 31
}
- uses_configuration {
- req_touch_screen: 3
- req_keyboard_type: 2
- req_hard_keyboard: -1
- req_navigation: 3
- req_five_way_nav: -1
- }
supports_screen {
screens: NORMAL
screens: LARGE
@@ -87,6 +80,7 @@ badging {
provided_components: "wallpaper"
provided_components: "accessibility"
provided_components: "print-service"
+ provided_components: "payment"
provided_components: "search"
provided_components: "document-provider"
provided_components: "notification-listener"
@@ -101,6 +95,13 @@ badging {
densities: 480
densities: 640
densities: 65534
+ uses_configurations {
+ req_touch_screen: 3
+ req_keyboard_type: 2
+ req_hard_keyboard: -1
+ req_navigation: 3
+ req_five_way_nav: -1
+ }
feature_groups {
features {
name: "android.hardware.bluetooth"
diff --git a/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
index c783f47f8142..6da6fc6f12c3 100644
--- a/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
+++ b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
@@ -40,13 +40,6 @@ badging {
min_sdk_version: 21
target_sdk_version: 31
}
- uses_configuration {
- req_touch_screen: 3
- req_keyboard_type: 2
- req_hard_keyboard: -1
- req_navigation: 3
- req_five_way_nav: -1
- }
supports_screen {
screens: NORMAL
screens: LARGE
@@ -87,6 +80,7 @@ badging {
provided_components: "wallpaper"
provided_components: "accessibility"
provided_components: "print-service"
+ provided_components: "payment"
provided_components: "search"
provided_components: "document-provider"
provided_components: "notification-listener"
@@ -101,6 +95,13 @@ badging {
densities: 480
densities: 640
densities: 65534
+ uses_configurations {
+ req_touch_screen: 3
+ req_keyboard_type: 2
+ req_hard_keyboard: -1
+ req_navigation: 3
+ req_five_way_nav: -1
+ }
feature_groups {
features {
name: "android.hardware.bluetooth"
diff --git a/tools/lint/framework/Android.bp b/tools/lint/framework/Android.bp
index 7f27e8a57d19..b7525030adc4 100644
--- a/tools/lint/framework/Android.bp
+++ b/tools/lint/framework/Android.bp
@@ -31,8 +31,6 @@ java_library_host {
],
static_libs: [
"AndroidCommonLint",
- // TODO: remove once b/236558918 is resolved and the below checks actually run globally
- "AndroidGlobalLintChecker",
],
kotlincflags: ["-Xjvm-default=all"],
}
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index c5cf0fb2f963..423a6843891e 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -19,9 +19,6 @@ package com.google.android.lint
import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
-import com.google.android.lint.aidl.EnforcePermissionDetector
-import com.google.android.lint.aidl.EnforcePermissionHelperDetector
-import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
import com.google.android.lint.parcel.SaferParcelChecker
import com.google.auto.service.AutoService
@@ -37,10 +34,6 @@ class AndroidFrameworkIssueRegistry : IssueRegistry() {
CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
CallingIdentityTokenDetector.ISSUE_RESULT_OF_CLEAR_IDENTITY_CALL_NOT_STORED_IN_VARIABLE,
CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED,
- EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION,
- EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
- EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
- SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG,